import { useCallback, useState, type FormEvent } from 'react'
import type { FieldValue, FieldValueMap, ResolvedFieldGroup } from './client.js'
import { referenceInputs } from './render.js'

export interface FieldValuesFormProps {
  groups: ResolvedFieldGroup[]
  initialValues?: Record<string, FieldValueMap>
  onSubmit: (groups: { groupId: string; values: FieldValueMap }[]) => void | Promise<void>
  disabled?: boolean
  errors?: Record<string, Record<string, string>>
}

function groupIdOf(group: ResolvedFieldGroup): string {
  return group.id ?? group.key
}

function seedValuesByGroup(
  groups: ResolvedFieldGroup[],
  initialValues?: Record<string, FieldValueMap>,
): Record<string, FieldValueMap> {
  const seeded: Record<string, FieldValueMap> = {}
  for (const group of groups) {
    const id = groupIdOf(group)
    seeded[id] = { ...(initialValues?.[id] ?? {}) }
  }
  return seeded
}

export function FieldValuesForm({
  groups,
  initialValues,
  onSubmit,
  disabled,
  errors,
}: FieldValuesFormProps) {
  const [valuesByGroup, setValuesByGroup] = useState(() => seedValuesByGroup(groups, initialValues))

  const setFieldValue = useCallback((groupId: string, key: string, value: FieldValue | undefined) => {
    setValuesByGroup((prev) => ({
      ...prev,
      [groupId]: { ...prev[groupId], [key]: value },
    }))
  }, [])

  const handleSubmit = useCallback(
    (e: FormEvent) => {
      e.preventDefault()
      const payload = groups.map((group) => {
        const groupId = groupIdOf(group)
        return { groupId, values: valuesByGroup[groupId] ?? {} }
      })
      void onSubmit(payload)
    },
    [onSubmit, valuesByGroup, groups],
  )

  return (
    <div className="fields-values-form" style={{ containerType: 'inline-size' }}>
      <form onSubmit={handleSubmit}>
        {groups.map((group) => {
          const groupId = groupIdOf(group)
          const groupValues = valuesByGroup[groupId] ?? {}
          return (
            <fieldset key={groupId} disabled={disabled} className="fields-values-form__group">
              {group.label ? <legend className="fields-values-form__legend">{group.label}</legend> : null}
              {group.fields.map((field) => {
                const Input = referenceInputs[field.type]
                const fieldError = errors?.[groupId]?.[field.key]
                return (
                  <div key={field.key} className="fields-values-form__field">
                    <Input
                      field={field}
                      value={groupValues[field.key]}
                      onChange={(v) => setFieldValue(groupId, field.key, v)}
                      error={fieldError}
                      disabled={disabled}
                    />
                    {fieldError ? (
                      <div role="alert" tabIndex={0} className="fields-values-form__error">
                        {fieldError}
                      </div>
                    ) : null}
                  </div>
                )
              })}
            </fieldset>
          )
        })}
        <button type="submit" disabled={disabled} className="fields-values-form__submit">
          Save fields
        </button>
      </form>
    </div>
  )
}
