import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import {
  Checkbox,
  FieldHint,
  FieldLabel,
  IconButton,
  SingleSelect,
  TextInput,
  TextArea,
  type SelectOption,
} from '@/ui'
import { TrashIcon, ArrowUpIcon, ArrowDownIcon } from '@phosphor-icons/react'
import type { PropertyDef, PropertyKind } from './types'
import { PROPERTY_KINDS } from './types'
import { useDictionaries, useDictionaryDetail } from '@/api/queries'

type Props = {
  prop: PropertyDef
  index: number
  total: number
  onChange: (next: PropertyDef) => void
  onRemove: () => void
  onMoveUp: () => void
  onMoveDown: () => void
}

export const PropertyEditor = ({
  prop,
  index,
  total,
  onChange,
  onRemove,
  onMoveUp,
  onMoveDown,
}: Props) => {
  const { t } = useTranslation()

  // 'opaque' исключён из dropdown — admin не может вручную выбрать сложный
  // тип. Поле получает opaque только через parseSchemaJson (когда уже было
  // в исходной schema). Для NEW поля admin использует обычные kinds.
  const kindOptions: SelectOption[] = PROPERTY_KINDS
    .filter((k) => k !== 'opaque')
    .map((k) => ({
      id: k,
      label: t(`schema.kind.${k}`),
    }))

  const update = (patch: Partial<PropertyDef>) => onChange({ ...prop, ...patch })

  return (
    <div className="border border-line rounded-lg p-3 space-y-3 bg-surface">
      <div className="flex items-start justify-between gap-2">
        <span className="text-cap text-mute">
          {t('schema.property')} #{index + 1}
        </span>
        <div className="flex items-center gap-1">
          <IconButton
            label={t('schema.moveUp')}
            variant="default"
            disabled={index === 0}
            icon={<ArrowUpIcon />}
            onClick={onMoveUp}
          />
          <IconButton
            label={t('schema.moveDown')}
            variant="default"
            disabled={index === total - 1}
            icon={<ArrowDownIcon />}
            onClick={onMoveDown}
          />
          <IconButton
            label={t('schema.delete')}
            variant="danger"
            icon={<TrashIcon />}
            onClick={onRemove}
          />
        </div>
      </div>

      <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
        <TextInput
          label={t('schema.name')}
          required
          placeholder="snake_case_key"
          pattern="^[a-z][a-z0-9_]*$"
          value={prop.name}
          onChange={(e) => update({ name: e.target.value })}
        />
        <SingleSelect
          label={t('schema.kind.label')}
          required
          options={kindOptions}
          value={prop.kind}
          onChange={(id) => update({ kind: id as PropertyKind })}
        />
      </div>

      <div className="flex flex-wrap gap-4">
        <Checkbox
          label={t('schema.required')}
          checked={prop.required}
          onChange={(e) => update({ required: e.target.checked })}
        />
        <Checkbox
          label={t('schema.unique')}
          description={t('schema.uniqueHint')}
          checked={prop.unique}
          onChange={(e) => update({ unique: e.target.checked })}
        />
      </div>

      <TextArea
        label={t('schema.description')}
        rows={2}
        value={prop.description ?? ''}
        onChange={(e) => update({ description: e.target.value })}
      />

      {prop.kind === 'opaque' && (
        <div className="bg-amber-50 border border-amber-200 rounded-md p-3 text-cell space-y-2">
          <div className="font-medium text-ink">
            {t('schema.opaque.title')}
          </div>
          <div className="text-ink-2">
            {t('schema.opaque.hint')}
          </div>
          <pre className="text-mono bg-surface border border-line rounded p-2 overflow-auto max-h-40">
            {JSON.stringify(prop.rawSchema ?? {}, null, 2)}
          </pre>
        </div>
      )}

      {(prop.kind === 'string') && (
        <div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
          <TextInput
            type="number"
            label="minLength"
            value={prop.minLength ?? ''}
            onChange={(e) => update({ minLength: e.target.value === '' ? undefined : Number(e.target.value) })}
          />
          <TextInput
            type="number"
            label="maxLength"
            value={prop.maxLength ?? ''}
            onChange={(e) => update({ maxLength: e.target.value === '' ? undefined : Number(e.target.value) })}
          />
          <TextInput
            label={t('schema.pattern')}
            placeholder="^[A-Z]{2}$"
            value={prop.pattern ?? ''}
            onChange={(e) => update({ pattern: e.target.value || undefined })}
          />
        </div>
      )}

      {(prop.kind === 'integer' || prop.kind === 'number') && (
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
          <TextInput
            type="number"
            label="minimum"
            value={prop.minimum ?? ''}
            onChange={(e) => update({ minimum: e.target.value === '' ? undefined : Number(e.target.value) })}
          />
          <TextInput
            type="number"
            label="maximum"
            value={prop.maximum ?? ''}
            onChange={(e) => update({ maximum: e.target.value === '' ? undefined : Number(e.target.value) })}
          />
        </div>
      )}

      {prop.kind === 'enum' && (
        <TextInput
          label={t('schema.enumValues')}
          hint={t('schema.enumValuesHint')}
          value={(prop.enumValues ?? []).join(', ')}
          onChange={(e) =>
            update({
              enumValues: e.target.value
                .split(',')
                .map((s) => s.trim())
                .filter(Boolean),
            })
          }
        />
      )}

      {prop.kind === 'reference' && (
        <ReferenceTargetPicker
          value={prop.referenceTarget}
          onChange={(next) => update({ referenceTarget: next })}
        />
      )}

      {prop.kind === 'array_string' && (
        <div className="space-y-3">
          <TextInput
            label={t('schema.arrayEnumOptional')}
            hint={t('schema.enumValuesHint')}
            value={(prop.enumValues ?? []).join(', ')}
            onChange={(e) =>
              update({
                enumValues: e.target.value
                  .split(',')
                  .map((s) => s.trim())
                  .filter(Boolean),
              })
            }
          />
          <Checkbox
            label="uniqueItems"
            checked={Boolean(prop.uniqueItems)}
            onChange={(e) => update({ uniqueItems: e.target.checked })}
          />
        </div>
      )}
    </div>
  )
}

/**
 * Picker для x-references = "dict.field". Левый select — список accessible
 * dictionaries, правый input — имя поля в target dict (обычно 'code').
 *
 * value/onChange работают с CSV формой "dict.field" чтобы родителю не пришлось
 * разносить state на 2 поля. Парсинг split('.', 2) — backend regex такой же.
 */
type ReferenceTargetPickerProps = {
  value: string | undefined
  onChange: (next: string) => void
}

const ReferenceTargetPicker = ({ value, onChange }: ReferenceTargetPickerProps) => {
  const { t } = useTranslation()
  const dictsQuery = useDictionaries()
  const [refDict = '', refField = ''] = (value ?? '').split('.', 2)
  // Fetch schema target dict чтобы показать реальные scalar поля как
  // options. Без этого юзер вписывал free-form имя (e.g. 'code') и
  // submit'ил schema с x-references на несуществующее поле → backend
  // при сохранении record искал `data.code` в target → 422
  // x_references_target_not_found. Реальный кейс: gs_sat_test03.sat =
  // spacecraft.code, но в spacecraft нет поля code, есть designator.
  const targetDetail = useDictionaryDetail(refDict || undefined)

  const dictOptions: SelectOption[] = useMemo(() => {
    const list = dictsQuery.data ?? []
    return list
      .map((d) => ({
        id: d.name,
        label: d.displayName ? `${d.name} — ${d.displayName}` : d.name,
      }))
      .sort((a, b) => a.label.localeCompare(b.label, 'ru'))
  }, [dictsQuery.data])

  // Eligible target fields: scalar non-localized, non-array/object.
  // FK имеет смысл только на простые ключевые поля (designator,
  // businessKey, code etc.). x-localized object и array не подходят
  // как identifier. businessKey включён как synthetic option — это
  // всегда unique identifier любого record, backend resolves его.
  const fieldOptions: SelectOption[] = useMemo(() => {
    const props = targetDetail.data?.schemaJson?.properties
    if (!props) return [{ id: 'businessKey', label: 'businessKey' }]
    const eligible: SelectOption[] = [{ id: 'businessKey', label: 'businessKey' }]
    for (const [key, prop] of Object.entries(props)) {
      if (Boolean(prop['x-localized'])) continue
      const type = prop.type
      if (type === 'array' || type === 'object') continue
      eligible.push({ id: key, label: key })
    }
    return eligible
  }, [targetDetail.data?.schemaJson])

  const handleDictChange = (next: string) => {
    // При смене target dict сбрасываем field на businessKey — universal
    // identifier что всегда существует на любом dict. Юзер потом выберет
    // более специфичное поле (designator / code / etc) из загруженного
    // списка fieldOptions.
    onChange(next ? `${next}.businessKey` : '')
  }

  const handleFieldChange = (next: string) => {
    onChange(refDict ? `${refDict}.${next}` : '')
  }

  const isValid = Boolean(refDict && refField)
  // Warn если выбранный field не существует в target schema (legacy
  // schemas с broken references, до этого fix'а можно было сохранить
  // такое значение). target dict ещё loading → не warn.
  const fieldExistsInTarget =
    !targetDetail.data || fieldOptions.some((opt) => opt.id === refField)

  return (
    <div className="border border-accent/20 bg-accent/4 rounded-md p-3 space-y-3">
      <div>
        <FieldLabel required>{t('schema.reference.title')}</FieldLabel>
        <FieldHint>{t('schema.reference.hint')}</FieldHint>
      </div>
      <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
        <SingleSelect
          label={t('schema.reference.targetDict')}
          required
          options={dictOptions}
          value={refDict}
          onChange={handleDictChange}
          placeholder={dictsQuery.isLoading ? '…' : '—'}
          disabled={dictsQuery.isLoading}
        />
        <SingleSelect
          label={t('schema.reference.targetField')}
          required
          options={fieldOptions}
          value={refField}
          onChange={handleFieldChange}
          placeholder={targetDetail.isLoading ? '…' : '—'}
          disabled={!refDict || targetDetail.isLoading}
        />
      </div>
      {!isValid && (
        <div className="text-cell text-mars">{t('schema.reference.required')}</div>
      )}
      {isValid && !fieldExistsInTarget && (
        <div className="text-cell text-mars">
          {t('schema.reference.targetFieldMissing', {
            defaultValue:
              'Поле «{{field}}» отсутствует в схеме «{{dict}}». Выберите существующее поле — иначе записи ссылающиеся на этот FK не пройдут валидацию.',
            field: refField,
            dict: refDict,
          })}
        </div>
      )}
    </div>
  )
}
