import type { ComponentType } from 'react'
import type {
  LegacyFieldDefinition as FieldDefinition,
  LegacyFieldType as FieldType,
  FieldValue,
  MediaRef,
  RelRef,
} from '@platform-modules/fields'

export interface FieldInputProps<F extends FieldDefinition = FieldDefinition> {
  field: F
  value: FieldValue | undefined
  onChange: (v: FieldValue | undefined) => void
  error?: string
  disabled?: boolean
}

export type FieldInputRegistry = {
  [T in FieldType]: ComponentType<FieldInputProps>
}

function Shell({ children }: { children: React.ReactNode }) {
  return <div style={{ containerType: 'inline-size' }}>{children}</div>
}

function TextInput({ field, value, onChange, disabled }: FieldInputProps) {
  return (
    <Shell>
      <input
        type="text"
        aria-label={field.label}
        value={typeof value === 'string' ? value : ''}
        disabled={disabled}
        onChange={(e) => onChange(e.target.value || undefined)}
      />
    </Shell>
  )
}

function TextAreaInput({ field, value, onChange, disabled }: FieldInputProps) {
  return (
    <Shell>
      <textarea
        aria-label={field.label}
        value={typeof value === 'string' ? value : ''}
        disabled={disabled}
        onChange={(e) => onChange(e.target.value || undefined)}
      />
    </Shell>
  )
}

function NumberInput({ field, value, onChange, disabled }: FieldInputProps) {
  return (
    <Shell>
      <input
        type="number"
        aria-label={field.label}
        value={typeof value === 'number' ? value : ''}
        disabled={disabled}
        onChange={(e) => {
          const raw = e.target.value
          onChange(raw === '' ? undefined : Number(raw))
        }}
      />
    </Shell>
  )
}

function BooleanInput({ field, value, onChange, disabled }: FieldInputProps) {
  return (
    <Shell>
      <input
        type="checkbox"
        aria-label={field.label}
        checked={value === true}
        disabled={disabled}
        onChange={(e) => onChange(e.target.checked)}
      />
    </Shell>
  )
}

function SelectInput({ field, value, onChange, disabled }: FieldInputProps) {
  const options = field.type === 'select' ? field.options : []
  const multiple = field.type === 'select' && field.multiple === true
  const selected = multiple
    ? Array.isArray(value)
      ? value.map(String)
      : []
    : typeof value === 'string'
      ? value
      : ''

  return (
    <Shell>
      <select
        aria-label={field.label}
        multiple={multiple}
        disabled={disabled}
        value={selected}
        onChange={(e) => {
          if (multiple) {
            onChange(Array.from(e.target.selectedOptions, (o) => o.value))
          } else {
            onChange(e.target.value || undefined)
          }
        }}
      >
        {!multiple ? <option value="">—</option> : null}
        {options.map((o) => (
          <option key={o.value} value={o.value}>
            {o.label}
          </option>
        ))}
      </select>
    </Shell>
  )
}

function DateInput({ field, value, onChange, disabled }: FieldInputProps) {
  const str =
    value instanceof Date
      ? value.toISOString().slice(0, 10)
      : typeof value === 'string'
        ? value
        : ''
  return (
    <Shell>
      <input
        type="date"
        aria-label={field.label}
        value={str}
        disabled={disabled}
        onChange={(e) => onChange(e.target.value ? new Date(e.target.value) : undefined)}
      />
    </Shell>
  )
}

function ColorInput({ field, value, onChange, disabled }: FieldInputProps) {
  const hex = typeof value === 'string' && value.startsWith('#') ? value.slice(0, 7) : '#000000'
  return (
    <Shell>
      <input
        type="color"
        aria-label={field.label}
        value={hex}
        disabled={disabled}
        onChange={(e) => onChange(e.target.value)}
      />
    </Shell>
  )
}

function UrlInput({ field, value, onChange, disabled }: FieldInputProps) {
  return (
    <Shell>
      <input
        type="url"
        aria-label={field.label}
        value={typeof value === 'string' ? value : ''}
        disabled={disabled}
        onChange={(e) => onChange(e.target.value || undefined)}
      />
    </Shell>
  )
}

function EmailInput({ field, value, onChange, disabled }: FieldInputProps) {
  return (
    <Shell>
      <input
        type="email"
        aria-label={field.label}
        value={typeof value === 'string' ? value : ''}
        disabled={disabled}
        onChange={(e) => onChange(e.target.value || undefined)}
      />
    </Shell>
  )
}

function MediaInput({ field, value, onChange, disabled }: FieldInputProps) {
  const media = !Array.isArray(value) && value && typeof value === 'object' && 'key' in value ? (value as MediaRef) : undefined
  return (
    <Shell>
      <input
        type="text"
        aria-label={field.label}
        placeholder="media key"
        value={media?.key ?? ''}
        disabled={disabled}
        onChange={(e) => {
          const key = e.target.value
          onChange(key ? { key, url: media?.url, mime: media?.mime, meta: media?.meta } : undefined)
        }}
      />
    </Shell>
  )
}

function RelationshipInput({ field, value, onChange, disabled }: FieldInputProps) {
  const rel = !Array.isArray(value) && value && typeof value === 'object' && 'entityType' in value ? (value as RelRef) : undefined
  // Each field edits its half of the pair independently — emit the combined ref built from the
  // current value of the OTHER half (defaulting to ''), and clear to undefined only when BOTH are
  // empty. (A guard requiring the other half to be set first would deadlock the first keystroke.)
  const emit = (entityType: string, entityId: string) =>
    onChange(entityType || entityId ? { entityType, entityId } : undefined)
  return (
    <Shell>
      <input
        type="text"
        aria-label={`${field.label} entity type`}
        placeholder="entityType"
        value={rel?.entityType ?? ''}
        disabled={disabled}
        onChange={(e) => emit(e.target.value, rel?.entityId ?? '')}
      />
      <input
        type="text"
        aria-label={`${field.label} entity id`}
        placeholder="entityId"
        value={rel?.entityId ?? ''}
        disabled={disabled}
        onChange={(e) => emit(rel?.entityType ?? '', e.target.value)}
      />
    </Shell>
  )
}

export const referenceInputs: FieldInputRegistry = {
  text: TextInput,
  textarea: TextAreaInput,
  number: NumberInput,
  boolean: BooleanInput,
  select: SelectInput,
  date: DateInput,
  color: ColorInput,
  url: UrlInput,
  email: EmailInput,
  media: MediaInput,
  relationship: RelationshipInput,
}
