import { useCallback, useEffect, useMemo, useState } from 'react'
import { FIELD_TYPES, FIELD_KEY_RE } from '@platform-modules/fields'
import type { EntityType, LegacyFieldDefinition as FieldDefinition, LegacyFieldGroup as FieldGroup, FieldType } from '@platform-modules/fields'
import { useFieldGroupBuilder } from './hooks.js'

export interface FieldGroupEditorProps {
  entityType: EntityType
  subType?: string
}

type GroupDraft = {
  key: string
  label: string
  location: FieldGroup['location']
  fields: FieldDefinition[]
}

function defaultField(): FieldDefinition {
  return { key: 'new_field', type: 'text', label: 'New field' }
}

function isValidKey(key: string): boolean {
  return FIELD_KEY_RE.test(key)
}


function withTypeDefaults(field: FieldDefinition, type: FieldType): FieldDefinition {
  const base = { ...field, type }
  if (type === 'select' && field.type !== 'select') {
    return { ...base, type: 'select', options: [{ value: 'option_a', label: 'Option A' }] }
  }
  if (type === 'relationship' && field.type !== 'relationship') {
    return { ...base, type: 'relationship', targetEntityType: 'content' }
  }
  return base as FieldDefinition
}

function GroupEditorSection({
  groupId,
  draft,
  onDraftChange,
  onSave,
  saving,
}: {
  groupId: string | undefined
  draft: GroupDraft
  onDraftChange: (next: GroupDraft) => void
  onSave: () => void
  saving: boolean
}) {
  const invalidKeys = draft.fields.filter((f) => !isValidKey(f.key))
  const hasInvalidKeys = invalidKeys.length > 0

  const updateField = useCallback(
    (index: number, patch: Partial<FieldDefinition>) => {
      const fields = draft.fields.map((f, i) => (i === index ? { ...f, ...patch } as FieldDefinition : f))
      onDraftChange({ ...draft, fields })
    },
    [draft, onDraftChange],
  )

  const setFieldType = useCallback(
    (index: number, type: FieldType) => {
      const fields = draft.fields.map((f, i) =>
        i === index ? withTypeDefaults(f, type) : f,
      )
      onDraftChange({ ...draft, fields })
    },
    [draft, onDraftChange],
  )

  const moveField = useCallback(
    (index: number, direction: -1 | 1) => {
      const target = index + direction
      if (target < 0 || target >= draft.fields.length) return
      const fields = [...draft.fields]
      const tmp = fields[index]!
      fields[index] = fields[target]!
      fields[target] = tmp
      onDraftChange({ ...draft, fields })
    },
    [draft, onDraftChange],
  )

  const removeField = useCallback(
    (index: number) => {
      onDraftChange({ ...draft, fields: draft.fields.filter((_, i) => i !== index) })
    },
    [draft, onDraftChange],
  )

  const addField = useCallback(() => {
    onDraftChange({ ...draft, fields: [...draft.fields, defaultField()] })
  }, [draft, onDraftChange])

  const updateSelectOption = useCallback(
    (fieldIndex: number, optionIndex: number, patch: { value?: string; label?: string }) => {
      const field = draft.fields[fieldIndex]
      if (!field || field.type !== 'select') return
      const options = field.options.map((o, i) =>
        i === optionIndex ? { ...o, ...patch } : o,
      )
      updateField(fieldIndex, { type: 'select', options })
    },
    [draft.fields, updateField],
  )

  const addSelectOption = useCallback(
    (fieldIndex: number) => {
      const field = draft.fields[fieldIndex]
      if (!field || field.type !== 'select') return
      const n = field.options.length + 1
      updateField(fieldIndex, {
        type: 'select',
        options: [...field.options, { value: `option_${n}`, label: `Option ${n}` }],
      })
    },
    [draft.fields, updateField],
  )

  return (
    <section className="fields-group-editor__group" aria-label={draft.label}>
      <h3 className="fields-group-editor__heading">{draft.label}</h3>
      <ul className="fields-group-editor__fields">
        {draft.fields.map((field, index) => {
          const isNewRow = field.key === 'new_field' && field.label === 'New field'
          const keyInvalid = !isValidKey(field.key)
          return (
            <li key={`${groupId ?? 'new'}-${index}`} className="fields-group-editor__row">
              <input
                type="text"
                aria-label={field.label}
                value={field.label}
                className="fields-group-editor__label"
                onChange={(e) => updateField(index, { label: e.target.value })}
              />
              <input
                type="text"
                id={`field-key-${field.key}`}
                aria-label="Field key"
                value={field.key}
                className="fields-group-editor__key"
                onChange={(e) => updateField(index, { key: e.target.value })}
              />
              {keyInvalid ? (
                <div role="alert" tabIndex={0} className="fields-group-editor__key-error">
                  Invalid field key — use lowercase letters, digits, and underscores; must start with a letter.
                </div>
              ) : null}
              <label className="fields-group-editor__required">
                <input
                  type="checkbox"
                  aria-label={`${field.label} required`}
                  checked={field.required === true}
                  onChange={(e) => updateField(index, { required: e.target.checked || undefined })}
                />
                Required
              </label>
              <select
                name={isNewRow ? 'field-type-new' : `field-type-${field.key}`}
                aria-label="Field type"
                value={field.type}
                className="fields-group-editor__type"
                onChange={(e) => setFieldType(index, e.target.value as FieldType)}
              >
                {FIELD_TYPES.map((t) => (
                  <option key={t} value={t}>
                    {t}
                  </option>
                ))}
              </select>
              {field.type === 'select' ? (
                <div className="fields-group-editor__options">
                  {field.options.map((opt: { value: string; label: string }, optIndex: number) => (
                    <div key={optIndex} className="fields-group-editor__option">
                      <input
                        type="text"
                        aria-label={`${field.label} option value`}
                        value={opt.value}
                        onChange={(e) =>
                          updateSelectOption(index, optIndex, { value: e.target.value })
                        }
                      />
                      <input
                        type="text"
                        aria-label={`${field.label} option label`}
                        value={opt.label}
                        onChange={(e) =>
                          updateSelectOption(index, optIndex, { label: e.target.value })
                        }
                      />
                    </div>
                  ))}
                  <button type="button" onClick={() => addSelectOption(index)}>
                    Add option
                  </button>
                </div>
              ) : null}
              <button
                type="button"
                aria-label={`Move ${field.label} up`}
                aria-disabled={index === 0}
                onClick={() => moveField(index, -1)}
              >
                Move up
              </button>
              <button
                type="button"
                aria-label={`Move ${field.label} down`}
                aria-disabled={index === draft.fields.length - 1}
                onClick={() => moveField(index, 1)}
              >
                Move down
              </button>
              <button type="button" aria-label={`Remove ${field.label}`} onClick={() => removeField(index)}>
                Remove field
              </button>
            </li>
          )
        })}
      </ul>
      <button type="button" className="fields-group-editor__add-field" onClick={addField}>
        Add field
      </button>
      <button
        type="button"
        className="fields-group-editor__save"
        disabled={hasInvalidKeys || saving}
        onClick={onSave}
      >
        Save group
      </button>
    </section>
  )
}

export function FieldGroupEditor({ entityType, subType }: FieldGroupEditorProps) {
  const { groups, loading, error, create, update } = useFieldGroupBuilder(entityType, { subType })
  const [drafts, setDrafts] = useState<Record<string, GroupDraft>>({})
  const [saving, setSaving] = useState(false)

  useEffect(() => {
    if (loading) return
    setDrafts((prev) => {
      const next = { ...prev }
      for (const g of groups) {
        const id = g.id ?? g.key
        if (!next[id]) {
          next[id] = {
            key: g.key,
            label: g.label,
            location: g.location,
            fields: g.fields.map((f) => ({ ...f })),
          }
        }
      }
      return next
    })
  }, [groups, loading])

  const handleSave = useCallback(
    async (groupId: string | undefined, draft: GroupDraft) => {
      setSaving(true)
      try {
        const payload: FieldGroup = {
          key: draft.key,
          label: draft.label,
          location: draft.location,
          fields: draft.fields,
        }
        if (groupId) {
          await update(groupId, payload)
        } else {
          await create(payload)
        }
      } finally {
        setSaving(false)
      }
    },
    [create, update],
  )

  const body = useMemo(() => {
    if (loading) return <p className="fields-group-editor__loading">Loading groups…</p>
    if (groups.length === 0) return <p className="fields-group-editor__empty">No field groups.</p>
    return groups.map((g) => {
      const id = g.id ?? g.key
      const draft = drafts[id]
      if (!draft) return null
      return (
        <GroupEditorSection
          key={id}
          groupId={g.id}
          draft={draft}
          saving={saving}
          onDraftChange={(next) => setDrafts((prev) => ({ ...prev, [id]: next }))}
          onSave={() => {
            const current = drafts[id]
            if (current) void handleSave(g.id, current)
          }}
        />
      )
    })
  }, [drafts, groups, handleSave, loading, saving])

  return (
    <div className="fields-group-editor" style={{ containerType: 'inline-size' }}>
      {error ? (
        <div role="alert" tabIndex={0} className="fields-group-editor__error">
          {error.message}
        </div>
      ) : null}
      {body}
    </div>
  )
}
