import {
  Checkbox,
  Grid,
  NumberInput,
  Select,
  Textarea,
  TextInput,
} from '@mantine/core';
import {
  conditionHolds,
  localized,
  type FormFieldConfig,
  type FormSectionConfig,
  type Vessel,
} from '@ema-platform/api';
import { CountrySelect } from '@ema-platform/ui';

interface Props {
  section: FormSectionConfig;
  values: Record<string, unknown>;
  formData: Record<string, Record<string, unknown>>;
  onChange: (key: string, value: unknown) => void;
  disabled?: boolean;
  /** Keyed `${sectionKey}.${fieldKey}` — shown under the offending field. */
  errors?: Record<string, string>;
  /** The applicant's registered vessels, for the vessel-picker field. */
  vessels?: Vessel[];
}

/**
 * Maps a Vessel's own fields onto whichever sibling fields the backend put
 * in the same section — same dual key/label matching the nationality prefill
 * in LicenseApplicationPage uses, so this doesn't depend on exact field-key
 * naming in the seeded formSchema.
 */
const VESSEL_FIELD_FILLERS: {
  matches: (label: string, key: string) => boolean;
  value: (vessel: Vessel) => unknown;
}[] = [
  { matches: (l, k) => k === 'registrationNumber' || l.includes('registration number'), value: (v) => v.registrationNumber },
  { matches: (l, k) => k === 'vesselName' || l.includes('vessel name'), value: (v) => v.name },
  { matches: (l, k) => k === 'category' || k === 'vesselCategory' || l.includes('vessel category'), value: (v) => v.category },
  { matches: (l, k) => k === 'vesselType' || l.includes('vessel type'), value: (v) => v.vesselType },
  { matches: (l, k) => k === 'imoNumber' || l.includes('imo'), value: (v) => v.imoNumber },
  { matches: (l, k) => k === 'hullNumber' || l.includes('hull number'), value: (v) => v.hullNumber },
  { matches: (l, k) => k === 'flagState' || l.includes('flag state') || l.includes('flag'), value: (v) => v.flagState },
  { matches: (l, k) => k === 'portOfRegistry' || l.includes('port of registry'), value: (v) => v.portOfRegistry },
  { matches: (l, k) => k === 'grossTonnage' || l.includes('gross tonnage'), value: (v) => v.grossTonnage },
  { matches: (l, k) => k === 'passengerCapacity' || l.includes('passenger capacity'), value: (v) => v.passengerCapacity },
  { matches: (l, k) => k === 'lengthMeters' || l.includes('length'), value: (v) => v.lengthMeters },
  { matches: (l, k) => k === 'yearBuilt' || l.includes('year built'), value: (v) => v.yearBuilt },
  { matches: (l, k) => k === 'engineType' || l.includes('engine type'), value: (v) => v.engineType },
  { matches: (l, k) => k === 'enginePowerKw' || l.includes('engine power'), value: (v) => v.enginePowerKw },
  { matches: (l, k) => k === 'numberOfEngines' || l.includes('number of engines'), value: (v) => v.numberOfEngines },
  { matches: (l, k) => k === 'hullMaterial' || l.includes('hull material'), value: (v) => v.hullMaterial },
];

function fillFromVessel(
  vessel: Vessel,
  fields: FormFieldConfig[],
  onChange: (key: string, value: unknown) => void,
) {
  for (const f of fields) {
    const label = localized(f.label).toLowerCase();
    const filler = VESSEL_FIELD_FILLERS.find((m) => m.matches(label, f.key));
    if (filler) onChange(f.key, filler.value(vessel) ?? '');
  }
}

/**
 * Renders one form section from the license type's configuration.
 *
 * Nothing here is Freight-Forwarder specific — adding a license type or moving
 * a field is a backend config change, which is the whole point of the
 * config-driven design.
 */
export function ConfigDrivenSection({
  section,
  values,
  formData,
  onChange,
  disabled,
  errors = {},
  vessels = [],
}: Props) {
  const fields = [...(section.fields ?? [])].sort(
    (a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0),
  );

  return (
    <Grid>
      {fields.map((field) => {
        if (!conditionHolds(field.showWhen, formData)) return null;

        const label = localized(field.label);
        const value = values?.[field.key];
        const error = errors[`${section.key}.${field.key}`];
        const common = {
          label,
          description: localized(field.helpText) || undefined,
          withAsterisk: field.required,
          error,
          // Read-only fields come from the user account and must not be edited.
          disabled: disabled || field.readOnly,
        };
        const span = field.type === 'TEXTAREA' ? 12 : 6;
        // Same field the profile Address tab collects — give it the same
        // searchable, flag-labeled picker instead of a plain option list.
        const isNationality = field.key === 'nationality' || label.toLowerCase().includes('nationality');
        // Options here can't be seeded statically — they're the applicant's
        // own vessel register, so this overrides whatever type the backend
        // configured, the same way nationality overrides SELECT above.
        const isVesselPicker = field.key === 'vesselId' || field.key === 'vessel' || /^(select\s+)?vessel$/i.test(label.trim());

        return (
          <Grid.Col span={{ base: 12, md: span }} key={field.key}>
            {isNationality ? (
              <CountrySelect
                {...common}
                demonym
                value={(value as string) ?? null}
                onChange={(v) => onChange(field.key, v)}
              />
            ) : isVesselPicker ? (
              // ponytail: swapped for a plain text input while testing —
              // vessels list is empty until the backend seed exists. Paste a
              // vessel id here to exercise the autofill; restore the Select
              // below once GET /vessels/mine returns real rows.
              // <Select
              //   {...common}
              //   placeholder="Select a registered vessel"
              //   data={vessels.map((v) => ({ value: v.id, label: `${v.name} — ${v.registrationNumber}` }))}
              //   value={(value as string) ?? null}
              //   onChange={(v) => {
              //     onChange(field.key, v);
              //     const vessel = vessels.find((x) => x.id === v);
              //     if (vessel) fillFromVessel(vessel, fields, onChange);
              //   }}
              //   searchable
              //   clearable={!field.required}
              // />
              <TextInput
                {...common}
                placeholder="Paste a vessel id (testing)"
                value={(value as string) ?? ''}
                onChange={(e) => {
                  const v = e.currentTarget.value;
                  onChange(field.key, v);
                  const vessel = vessels.find((x) => x.id === v);
                  if (vessel) fillFromVessel(vessel, fields, onChange);
                }}
              />
            ) : field.type === 'SELECT' ? (
              <Select
                {...common}
                data={(field.options ?? []).map((o) => ({
                  value: o.value,
                  label: localized(o.label),
                }))}
                value={(value as string) ?? null}
                onChange={(v) => onChange(field.key, v)}
                clearable={!field.required}
              />
            ) : field.type === 'BOOLEAN' ? (
              <Checkbox
                label={label}
                error={error}
                disabled={common.disabled}
                checked={Boolean(value)}
                onChange={(e) => onChange(field.key, e.currentTarget.checked)}
                mt="md"
              />
            ) : field.type === 'NUMBER' || field.type === 'MONEY' ? (
              <NumberInput
                {...common}
                value={(value as number) ?? ''}
                onChange={(v) => onChange(field.key, v === '' ? null : Number(v))}
                // Deliberately not clamped with min/max: Mantine would rewrite
                // the entered figure on blur, quietly turning a capital of
                // 900,000 into the 1,500,000 threshold. Validation reports the
                // problem instead, leaving what the applicant typed intact.
                thousandSeparator={field.type === 'MONEY' ? ',' : undefined}
              />
            ) : field.type === 'DATE' ? (
              <TextInput
                {...common}
                type="date"
                value={(value as string) ?? ''}
                onChange={(e) => onChange(field.key, e.currentTarget.value)}
              />
            ) : field.type === 'TEXTAREA' ? (
              <Textarea
                {...common}
                autosize
                minRows={3}
                value={(value as string) ?? ''}
                onChange={(e) => onChange(field.key, e.currentTarget.value)}
              />
            ) : (
              <TextInput
                {...common}
                type={field.type === 'EMAIL' ? 'email' : 'text'}
                value={(value as string) ?? ''}
                onChange={(e) => onChange(field.key, e.currentTarget.value)}
              />
            )}
          </Grid.Col>
        );
      })}
    </Grid>
  );
}
