import React, { useState, useEffect, useRef } from 'react';
import { experimentsApi } from '../api/client';
import Button from './ui/Button';
import Alert from './ui/Alert';

// ── helpers ────────────────────────────────────────────────────────────────────

function toKey(label) {
  return label.toLowerCase().trim()
    .replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '').slice(0, 64);
}

// ── Tag chip ───────────────────────────────────────────────────────────────────

function TagChip({ value, onRemove }) {
  return (
    <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-indigo-50 border border-indigo-200 text-indigo-700 text-xs font-medium">
      {value}
      <button
        type="button"
        aria-label={`Remove tag ${value}`}
        onClick={onRemove}
        className="text-indigo-400 hover:text-indigo-700 leading-none"
      >✕</button>
    </span>
  );
}

// ── Inline tag editor (expanded panel below a field row) ──────────────────────

function TagPanel({ field, onChange, onAddTag, onRemoveTag }) {
  const [draft, setDraft] = useState('');
  const [err, setErr] = useState('');
  const disabled = !!field.tagsDisabled;

  function commit() {
    const v = draft.trim();
    if (!v) { setErr('Tag cannot be empty'); return; }
    if (v.length > 512) { setErr('Tag must be ≤512 characters'); return; }
    if ((field.tags ?? []).includes(v)) { setErr('Tag already exists'); return; }
    setErr('');
    onAddTag(field.fieldId, v);
    setDraft('');
  }

  return (
    <div className="px-4 pb-3 pt-2 bg-indigo-50/40 border-t border-indigo-100 rounded-b-lg">
      <div className="flex items-center justify-between mb-2">
        <p className="text-xs font-semibold text-indigo-600 uppercase tracking-wide">Quick-fill tags</p>
        <label className="flex items-center gap-1.5 text-xs text-gray-500 cursor-pointer select-none">
          <input
            type="checkbox"
            checked={disabled}
            onChange={(e) => onChange({ ...field, tagsDisabled: e.target.checked })}
            className="w-3.5 h-3.5 accent-indigo-600"
          />
          Disable tagging
        </label>
      </div>

      {!disabled && (
        <>
          <div className="flex flex-wrap gap-1.5 mb-2 min-h-[24px]">
            {(field.tags ?? []).length === 0 && (
              <span className="text-xs text-gray-400 italic">No tags yet.</span>
            )}
            {(field.tags ?? []).map((t) => (
              <TagChip key={t} value={t} onRemove={() => onRemoveTag(field.fieldId, t)} />
            ))}
          </div>

          <div className="flex gap-2 items-start">
            <div className="flex-1">
              <input
                aria-label={`Add tag for ${field.label}`}
                className={`w-full text-sm rounded border px-2 py-1 focus:outline-none focus:ring-2 focus:ring-indigo-400 ${err ? 'border-red-400' : 'border-gray-300'}`}
                placeholder="Type a tag value…"
                value={draft}
                onChange={(e) => { setDraft(e.target.value); setErr(''); }}
                onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); commit(); } }}
              />
              {err && <p className="text-xs text-red-500 mt-0.5">{err}</p>}
            </div>
            <Button size="sm" type="button" onClick={commit}>+ Add</Button>
          </div>
        </>
      )}

      {disabled && (
        <p className="text-xs text-gray-400 italic">Tagging is disabled for this field. Existing tags are preserved.</p>
      )}
    </div>
  );
}

// ── Single field row (draggable) ───────────────────────────────────────────────

function FieldRow({
  field, index, total,
  onChange, onToggle, onRemove, onAddTag, onRemoveTag,
  allKeys,
  // drag props
  onDragStart, onDragEnter, onDragEnd,
  isDragOver,
}) {
  const [labelDraft, setLabelDraft] = useState(field.label);
  const [labelError, setLabelError] = useState('');
  const [showTags, setShowTags] = useState(false);

  useEffect(() => { setLabelDraft(field.label); }, [field.label]);

  function commitLabel() {
    const trimmed = labelDraft.trim();
    if (!trimmed) { setLabelError('Label cannot be empty'); return; }
    if (trimmed.length > 128) { setLabelError('Label must be ≤128 characters'); return; }
    if (!field.builtin) {
      const newKey = toKey(trimmed);
      if (!newKey) { setLabelError('Label must contain at least one alphanumeric character'); return; }
      if (allKeys.find((k) => k !== field.key && k === newKey)) {
        setLabelError('A field with this name already exists'); return;
      }
    }
    setLabelError('');
    onChange({ ...field, label: trimmed, key: field.builtin ? field.key : toKey(trimmed) });
  }

  const tagCount = (field.tags ?? []).length;

  return (
    <div
      className={`rounded-lg border transition-all ${isDragOver ? 'border-blue-400 shadow-md scale-[1.01]' : 'border-gray-200'} ${field.active ? 'bg-white' : 'bg-gray-50 opacity-60'}`}
      draggable
      onDragStart={() => onDragStart(index)}
      onDragEnter={() => onDragEnter(index)}
      onDragEnd={onDragEnd}
      onDragOver={(e) => e.preventDefault()}
    >
      {/* Main row */}
      <div className="flex items-center gap-3 px-3 py-2.5">
        {/* Drag handle */}
        <span
          className="text-gray-300 hover:text-gray-500 cursor-grab active:cursor-grabbing select-none text-lg leading-none"
          title="Drag to reorder"
          aria-label="Drag handle"
        >⠿</span>

        {/* Label input */}
        <div className="flex-1 min-w-0">
          <input
            aria-label={`Field label for ${field.key}`}
            className={`w-full text-sm rounded border px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500 ${labelError ? 'border-red-400' : 'border-gray-300'} ${!field.active ? 'bg-gray-100' : 'bg-white'}`}
            value={labelDraft}
            disabled={!field.active}
            onChange={(e) => { setLabelDraft(e.target.value); setLabelError(''); }}
            onBlur={commitLabel}
            onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); commitLabel(); } }}
          />
          {labelError && <p className="text-xs text-red-500 mt-0.5">{labelError}</p>}
          <p className="text-xs text-gray-400 mt-0.5 font-mono">
            key: {field.key}
            {field.fieldId && (
              <span className="ml-2 text-gray-300" title={`Stable field ID: ${field.fieldId}`}>
                · id: {field.fieldId.slice(0, 8)}…
              </span>
            )}
          </p>
        </div>

        {/* Type selector */}
        <select
          aria-label={`Field type for ${field.key}`}
          className="text-xs border border-gray-200 rounded px-2 py-1 bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 disabled:bg-gray-100"
          value={field.type}
          disabled={!field.active}
          onChange={(e) => onChange({ ...field, type: e.target.value })}
        >
          <option value="text">Short text</option>
          <option value="textarea">Long text</option>
        </select>

        {/* Width (text fields only) */}
        {field.type === 'text' && (
          <select
            aria-label={`Width for ${field.key}`}
            title="Input width in the entry form"
            className="text-xs border border-gray-200 rounded px-2 py-1 bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 disabled:bg-gray-100"
            value={field.width ?? 100}
            disabled={!field.active}
            onChange={(e) => onChange({ ...field, width: Number(e.target.value) })}
          >
            <option value={100}>Full</option>
            <option value={75}>3/4</option>
            <option value={67}>2/3</option>
            <option value={50}>1/2</option>
            <option value={42}>5/12</option>
            <option value={33}>1/3</option>
            <option value={25}>1/4</option>
            <option value={17}>1/6</option>
            <option value={8}>1/12</option>
          </select>
        )}

        {/* Abbreviation */}
        <input
          aria-label={`Abbreviation for ${field.key}`}
          className="text-xs border border-gray-200 rounded px-2 py-1 w-20 focus:outline-none focus:ring-1 focus:ring-blue-400 disabled:bg-gray-100"
          placeholder="Abbr"
          title="Column abbreviation (≤10 chars)"
          maxLength={10}
          value={field.abbr ?? ''}
          disabled={!field.active}
          onChange={(e) => onChange({ ...field, abbr: e.target.value })}
        />

        {/* Unit */}
        <input
          aria-label={`Unit for ${field.key}`}
          className="text-xs border border-gray-200 rounded px-2 py-1 w-20 focus:outline-none focus:ring-1 focus:ring-blue-400 disabled:bg-gray-100"
          placeholder="Unit"
          title="Measurement unit (≤10 chars)"
          maxLength={10}
          value={field.unit ?? ''}
          disabled={!field.active}
          onChange={(e) => onChange({ ...field, unit: e.target.value })}
        />

        {/* Tags toggle */}
        <button
          type="button"
          title={showTags ? 'Hide tags' : 'Manage quick-fill tags'}
          aria-label={`Manage tags for ${field.label}`}
          onClick={() => setShowTags((v) => !v)}
          className={`relative text-sm px-2 py-1 rounded border transition-colors ${
            showTags
              ? 'border-indigo-400 bg-indigo-50 text-indigo-700'
              : 'border-gray-200 text-gray-500 hover:bg-indigo-50 hover:border-indigo-300 hover:text-indigo-700'
          }`}
        >
          🏷
          {tagCount > 0 && (
            <span className="absolute -top-1.5 -right-1.5 bg-indigo-600 text-white text-[10px] font-bold rounded-full w-4 h-4 flex items-center justify-center leading-none">
              {tagCount > 9 ? '9+' : tagCount}
            </span>
          )}
        </button>

        {/* Hide / Show */}
        <button
          type="button"
          title={field.active ? 'Hide field' : 'Show field'}
          aria-label={field.active ? `Hide ${field.label}` : `Show ${field.label}`}
          onClick={() => onToggle(field.fieldId)}
          className={`text-sm px-2 py-1 rounded border transition-colors ${
            field.active
              ? 'border-gray-200 text-gray-500 hover:bg-yellow-50 hover:border-yellow-300 hover:text-yellow-700'
              : 'border-green-200 text-green-600 hover:bg-green-50'
          }`}
        >
          {field.active ? 'Hide' : 'Show'}
        </button>

        {/* Remove (custom fields only) */}
        {!field.builtin && (
          <button
            type="button"
            title="Remove field permanently"
            aria-label={`Remove ${field.label}`}
            onClick={() => onRemove(field.fieldId)}
            className="text-sm px-2 py-1 rounded border border-red-200 text-red-500 hover:bg-red-50 transition-colors"
          >✕</button>
        )}
      </div>

      {/* Tag panel (collapsible) */}
      {showTags && (
        <TagPanel field={field} onChange={onChange} onAddTag={onAddTag} onRemoveTag={onRemoveTag} />
      )}
    </div>
  );
}

// ── Main TemplateEditor ────────────────────────────────────────────────────────

export default function TemplateEditor({ experimentId, onClose, loadFn, saveFn }) {
  const [fields, setFields] = useState([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState(null);
  const [success, setSuccess] = useState(false);

  // Add-field form
  const [newLabel, setNewLabel] = useState('');
  const [newType, setNewType] = useState('text');
  const [addError, setAddError] = useState('');

  // Drag state
  const dragIndex = useRef(null);
  const [dragOverIndex, setDragOverIndex] = useState(null);

  useEffect(() => {
    const fn = loadFn ?? (() => experimentsApi.getTemplate(experimentId));
    fn().then(setFields).catch((e) => setError(e.message)).finally(() => setLoading(false));
  }, [experimentId]);

  // ── field mutation helpers ─────────────────────────────────────────────────

  function updateField(updated) {
    setFields((prev) => prev.map((f) => f.fieldId === updated.fieldId ? updated : f));
  }
  function toggleField(fieldId) {
    setFields((prev) => prev.map((f) => f.fieldId === fieldId ? { ...f, active: !f.active } : f));
  }
  function removeField(fieldId) {
    setFields((prev) => prev.filter((f) => f.fieldId !== fieldId));
  }

  // ── tag helpers ────────────────────────────────────────────────────────────

  function addTag(fieldId, value) {
    setFields((prev) => prev.map((f) =>
      f.fieldId === fieldId
        ? { ...f, tags: [...(f.tags ?? []), value] }
        : f
    ));
  }
  function removeTag(fieldId, value) {
    setFields((prev) => prev.map((f) =>
      f.fieldId === fieldId
        ? { ...f, tags: (f.tags ?? []).filter((t) => t !== value) }
        : f
    ));
  }

  // ── drag handlers ──────────────────────────────────────────────────────────

  function handleDragStart(index) {
    dragIndex.current = index;
  }
  function handleDragEnter(index) {
    setDragOverIndex(index);
  }
  function handleDragEnd() {
    const from = dragIndex.current;
    const to   = dragOverIndex;
    if (from !== null && to !== null && from !== to) {
      setFields((prev) => {
        const next = [...prev];
        const [moved] = next.splice(from, 1);
        next.splice(to, 0, moved);
        return next;
      });
    }
    dragIndex.current = null;
    setDragOverIndex(null);
  }

  // ── add new field ──────────────────────────────────────────────────────────

  function addField() {
    const trimmed = newLabel.trim();
    if (!trimmed) { setAddError('Field name is required'); return; }
    const key = toKey(trimmed);
    if (!key) { setAddError('Name must contain at least one alphanumeric character'); return; }
    if (fields.some((f) => f.key === key)) { setAddError(`A field with key "${key}" already exists`); return; }
    setAddError('');
    const fieldId = crypto.randomUUID();
    setFields((prev) => [...prev, { fieldId, key, label: trimmed, type: newType, builtin: false, active: true, tags: [] }]);
    setNewLabel('');
    setNewType('text');
  }

  // ── save ───────────────────────────────────────────────────────────────────

  async function save() {
    setSaving(true);
    setError(null);
    try {
      const fn = saveFn ?? ((f) => experimentsApi.updateTemplate(experimentId, f));
      await fn(fields);
      setSuccess(true);
      setTimeout(() => { setSuccess(false); onClose(fields); }, 700);
    } catch (e) {
      setError(e.message);
    } finally {
      setSaving(false);
    }
  }

  const allKeys = fields.map((f) => f.key);

  return (
    <div className="space-y-4">
      {loading && <p className="text-sm text-gray-400">Loading template…</p>}
      {error   && <Alert type="error"   message={error}          onDismiss={() => setError(null)} />}
      {success && <Alert type="success" message="Template saved!" />}

      {!loading && (
        <>
          {/* Field list */}
          <div className="space-y-2">
            {fields.length === 0 && (
              <p className="text-sm text-gray-400 italic text-center py-4">No fields yet. Add one below.</p>
            )}
            {fields.map((field, index) => (
              <FieldRow
                key={field.fieldId}
                field={field}
                index={index}
                total={fields.length}
                onChange={updateField}
                onToggle={toggleField}
                onRemove={removeField}
                onAddTag={addTag}
                onRemoveTag={removeTag}
                allKeys={allKeys}
                onDragStart={handleDragStart}
                onDragEnter={handleDragEnter}
                onDragEnd={handleDragEnd}
                isDragOver={dragOverIndex === index}
              />
            ))}
          </div>

          {/* Add new field */}
          <div className="border-t pt-4">
            <p className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2">Add New Field</p>
            <div className="flex gap-2 items-start">
              <div className="flex-1">
                <input
                  aria-label="New field name"
                  className={`w-full text-sm rounded border px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 ${addError ? 'border-red-400' : 'border-gray-300'}`}
                  placeholder="Field name, e.g. Blood Pressure"
                  value={newLabel}
                  onChange={(e) => { setNewLabel(e.target.value); setAddError(''); }}
                  onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addField(); } }}
                />
                {addError && <p className="text-xs text-red-500 mt-0.5">{addError}</p>}
              </div>
              <select
                aria-label="New field type"
                className="text-sm border border-gray-300 rounded px-2 py-2 bg-white focus:outline-none focus:ring-1 focus:ring-blue-400"
                value={newType}
                onChange={(e) => setNewType(e.target.value)}
              >
                <option value="text">Short text</option>
                <option value="textarea">Long text</option>
              </select>
              <Button size="sm" type="button" onClick={addField}>+ Add</Button>
            </div>
          </div>

          <p className="text-xs text-gray-400">
            Drag <span className="font-mono">⠿</span> to reorder · <strong>Hide</strong> removes a builtin field from forms while preserving its data · <strong>🏷</strong> manages quick-fill tags
          </p>

          {/* Actions */}
          <div className="flex justify-end gap-3 border-t pt-4">
            <Button variant="secondary" onClick={() => onClose(null)} disabled={saving}>Cancel</Button>
            <Button onClick={save} loading={saving}>Save Template</Button>
          </div>
        </>
      )}
    </div>
  );
}
