'use client'

/**
 * Fields tab of the Form Schema drawer. Renders the form's field list with
 * drag-to-reorder (dnd-kit, keyboard-accessible) plus an inline editor for the
 * selected field. The parent owns the `fields` array and persistence; this
 * panel is a controlled editor that calls `onChange` with the next array.
 */
import {
  DndContext,
  KeyboardSensor,
  PointerSensor,
  closestCenter,
  useSensor,
  useSensors,
  type DragEndEvent,
} from '@dnd-kit/core'
import {
  SortableContext,
  sortableKeyboardCoordinates,
  useSortable,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { ChevronDown, GripVertical, Plus, Trash2 } from 'lucide-react'
import * as Switch from '@radix-ui/react-switch'
import { useId, useState } from 'react'
import type { FormField, FormFieldType } from '../../lib/forms-service.js'
import { FieldTypeBadge, FormsEmptyState } from './primitives.js'

const FIELD_TYPES: { value: FormFieldType; label: string }[] = [
  { value: 'text', label: 'Text' },
  { value: 'email', label: 'Email' },
  { value: 'phone', label: 'Phone' },
  { value: 'textarea', label: 'Textarea' },
  { value: 'select', label: 'Select' },
  { value: 'multiselect', label: 'Multi-select' },
  { value: 'radio', label: 'Radio' },
  { value: 'checkbox', label: 'Checkbox' },
  { value: 'date', label: 'Date' },
  { value: 'number', label: 'Number' },
  { value: 'url', label: 'URL' },
  { value: 'consent', label: 'Consent' },
  { value: 'file', label: 'File upload' },
  { value: 'hidden', label: 'Hidden' },
  { value: 'richtext', label: 'Content block' },
  { value: 'divider', label: 'Divider / heading' },
]

const OPTION_TYPES: FormFieldType[] = ['select', 'multiselect', 'radio']

function slugifyKey(label: string): string {
  return label
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, '_')
    .replace(/^_+|_+$/g, '')
}

function makeId(): string {
  if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) return crypto.randomUUID()
  return `f_${Math.random().toString(36).slice(2)}`
}

export function FieldsPanel({
  fields,
  onChange,
  hasSubmissions,
}: {
  fields: FormField[]
  onChange: (next: FormField[]) => void
  /** When the form already has submissions, key renames/deletes are riskier. */
  hasSubmissions: boolean
}) {
  const [editingId, setEditingId] = useState<string | null>(null)

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
  )

  function handleDragEnd(event: DragEndEvent) {
    const { active, over } = event
    if (!over || active.id === over.id) return
    const ids = fields.map((f) => f.id)
    const from = ids.indexOf(String(active.id))
    const to = ids.indexOf(String(over.id))
    if (from === -1 || to === -1) return
    const next = fields.slice()
    const [moved] = next.splice(from, 1)
    next.splice(to, 0, moved!)
    onChange(next.map((f, i) => ({ ...f, sortOrder: i })))
  }

  function updateField(id: string, patch: Partial<FormField>) {
    onChange(fields.map((f) => (f.id === id ? { ...f, ...patch } : f)))
  }

  function deleteField(id: string) {
    onChange(fields.filter((f) => f.id !== id))
    if (editingId === id) setEditingId(null)
  }

  function addField() {
    const id = makeId()
    const next: FormField = {
      id,
      label: 'New Field',
      key: `field_${fields.length + 1}`,
      type: 'text',
      required: false,
      sortOrder: fields.length,
    }
    onChange([...fields, next])
    setEditingId(id)
  }

  return (
    <div className="space-y-3">
      {fields.length === 0 ? (
        <FormsEmptyState
          title="No fields yet"
          description="Add your first field to start building this form."
        />
      ) : (
        <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
          <SortableContext items={fields.map((f) => f.id)} strategy={verticalListSortingStrategy}>
            <ul className="space-y-2">
              {fields.map((field) => (
                <SortableFieldRow
                  key={field.id}
                  field={field}
                  editing={editingId === field.id}
                  hasSubmissions={hasSubmissions}
                  onToggleEdit={() => setEditingId((cur) => (cur === field.id ? null : field.id))}
                  onUpdate={(patch) => updateField(field.id, patch)}
                  onDelete={() => deleteField(field.id)}
                />
              ))}
            </ul>
          </SortableContext>
        </DndContext>
      )}

      <button
        type="button"
        onClick={addField}
        className="border-border text-foreground hover:bg-accent flex w-full items-center justify-center gap-2 rounded-lg border border-dashed px-3 py-2.5 text-sm font-medium transition-colors"
      >
        <Plus className="h-4 w-4" aria-hidden />
        Add Field
      </button>
    </div>
  )
}

function SortableFieldRow({
  field,
  editing,
  hasSubmissions,
  onToggleEdit,
  onUpdate,
  onDelete,
}: {
  field: FormField
  editing: boolean
  hasSubmissions: boolean
  onToggleEdit: () => void
  onUpdate: (patch: Partial<FormField>) => void
  onDelete: () => void
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: field.id,
  })
  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    zIndex: isDragging ? 10 : undefined,
  }
  const needsOptions = OPTION_TYPES.includes(field.type)

  return (
    <li ref={setNodeRef} style={style}>
      <div
        className={`border-border bg-card rounded-lg border ${isDragging ? 'shadow-md' : ''} ${editing ? 'ring-primary/30 ring-1' : ''}`}
      >
        <div className="flex items-center gap-2 px-2.5 py-2">
          <button
            type="button"
            className="text-muted-foreground hover:text-foreground focus-visible:ring-ring shrink-0 cursor-grab touch-none rounded focus-visible:ring-2 focus-visible:outline-none"
            aria-label={`Drag to reorder ${field.label}`}
            {...attributes}
            {...listeners}
          >
            <GripVertical className="h-4 w-4" aria-hidden />
          </button>

          <button
            type="button"
            onClick={onToggleEdit}
            className="flex min-w-0 flex-1 items-center gap-2 text-left"
            aria-expanded={editing}
          >
            <span className="min-w-0">
              <span className="text-foreground block truncate text-sm font-medium">
                {field.label || '(untitled)'}
              </span>
              <span className="text-muted-foreground block truncate font-mono text-xs">
                {field.key}
              </span>
            </span>
          </button>

          <FieldTypeBadge type={field.type} />
          {field.required && (
            <span className="bg-muted text-muted-foreground rounded px-1.5 py-0.5 text-[10px] font-medium uppercase">
              Required
            </span>
          )}

          <button
            type="button"
            onClick={onToggleEdit}
            className="text-muted-foreground hover:text-foreground focus-visible:ring-ring shrink-0 rounded p-1 focus-visible:ring-2 focus-visible:outline-none"
            aria-label={`${editing ? 'Collapse' : 'Edit'} ${field.label}`}
          >
            <ChevronDown
              className={`h-4 w-4 transition-transform ${editing ? '' : '-rotate-90'}`}
              aria-hidden
            />
          </button>
          <button
            type="button"
            onClick={onDelete}
            className="text-muted-foreground hover:text-destructive focus-visible:ring-ring shrink-0 rounded p-1 focus-visible:ring-2 focus-visible:outline-none"
            aria-label={`Delete ${field.label}`}
          >
            <Trash2 className="h-4 w-4" aria-hidden />
          </button>
        </div>

        {editing && (
          <FieldEditor
            field={field}
            hasSubmissions={hasSubmissions}
            needsOptions={needsOptions}
            onUpdate={onUpdate}
          />
        )}
      </div>
    </li>
  )
}

function FieldEditor({
  field,
  hasSubmissions,
  needsOptions,
  onUpdate,
}: {
  field: FormField
  hasSubmissions: boolean
  needsOptions: boolean
  onUpdate: (patch: Partial<FormField>) => void
}) {
  const reqId = useId()
  const optionsText = (field.options ?? []).map((o) => o.label).join('\n')

  return (
    <div className="border-border space-y-3 border-t px-3 py-3">
      <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
        <Labeled label="Label">
          <input
            type="text"
            value={field.label}
            onChange={(e) => {
              const label = e.target.value
              // Auto-derive the key from the label until the form has data and
              // until the user has clearly customised the key.
              const autoKey = slugifyKey(field.label)
              const patch: Partial<FormField> = { label }
              if (!hasSubmissions && (field.key === autoKey || !field.key)) {
                patch.key = slugifyKey(label)
              }
              onUpdate(patch)
            }}
            className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none"
          />
        </Labeled>
        <Labeled
          label="Key"
          hint={hasSubmissions ? 'Renaming affects existing entries & exports' : undefined}
        >
          <input
            type="text"
            value={field.key}
            onChange={(e) => onUpdate({ key: slugifyKey(e.target.value) })}
            className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 font-mono text-sm focus-visible:ring-2 focus-visible:outline-none"
          />
        </Labeled>
        <Labeled label="Type">
          <select
            value={field.type}
            onChange={(e) => onUpdate({ type: e.target.value as FormFieldType })}
            className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none"
          >
            {FIELD_TYPES.map((t) => (
              <option key={t.value} value={t.value}>
                {t.label}
              </option>
            ))}
          </select>
        </Labeled>
        <Labeled label="Placeholder">
          <input
            type="text"
            value={field.placeholder ?? ''}
            onChange={(e) => onUpdate({ placeholder: e.target.value })}
            className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none"
          />
        </Labeled>
      </div>

      <Labeled label="Help text">
        <input
          type="text"
          value={field.helpText ?? ''}
          onChange={(e) => onUpdate({ helpText: e.target.value })}
          className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none"
        />
      </Labeled>

      {needsOptions && (
        <Labeled label="Options" hint="One per line">
          <textarea
            rows={3}
            value={optionsText}
            onChange={(e) =>
              onUpdate({
                options: e.target.value
                  .split('\n')
                  .map((line) => line.trim())
                  .filter(Boolean)
                  .map((label) => ({ label, value: slugifyKey(label) })),
              })
            }
            className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none"
          />
        </Labeled>
      )}

      <div className="flex items-center justify-between">
        <label htmlFor={reqId} className="text-foreground text-sm font-medium">
          Required
        </label>
        <Switch.Root
          id={reqId}
          checked={field.required}
          onCheckedChange={(v) => onUpdate({ required: v })}
          className="bg-input-background data-[state=checked]:bg-primary focus-visible:ring-ring relative h-[18px] w-8 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none"
        >
          <Switch.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" />
        </Switch.Root>
      </div>
    </div>
  )
}

function Labeled({
  label,
  hint,
  children,
}: {
  label: string
  hint?: string
  children: React.ReactNode
}) {
  return (
    <label className="block">
      <span className="text-muted-foreground mb-1 block text-xs font-medium">{label}</span>
      {children}
      {hint && <span className="text-warning mt-1 block text-xs">{hint}</span>}
    </label>
  )
}
