'use client';
import { FunctionComponent, useEffect } from 'react';
import { useTranslations } from 'next-intl';
import { useForm, FormProvider } from 'react-hook-form';
import Stack from '@mui/material/Stack';
import { AppButton } from '@/components/common';
import { RhfChipSelect, RhfControlGroup, RhfTextField } from '@/components/common/form';
import GenderToggle from '@/components/GenderToggle';
import RelationSelect from '@/components/RelationSelect';
import { digitsOnly } from '@/utils';
import { CONDITION_CODES, RELATION_CODES } from '@/services/patients/constants';
import { ageToBirthDate, birthDateToAge } from '@/services/patients/age';
import type { ConditionCode, CreatePatientInput, Gender, Patient, Relation } from '@/services/patients/types';

const MAX_AGE = 120;
const MAX_AGE_DIGITS = 3;

export interface PatientFormProps {
  /** Prefill for edit, or a relation carried from the onboarding relation step. */
  initial?: Partial<Pick<Patient, 'displayName' | 'firstName' | 'lastName' | 'birthDate' | 'gender' | 'conditions' | 'relation'>>;
  /** Show the relation picker (E1 add/edit). Onboarding hides it — A3 already chose the relation. */
  showRelation?: boolean;
  submitLabel: string;
  submitting?: boolean;
  onSubmit: (input: CreatePatientInput) => void;
  onCancel?: () => void;
  cancelLabel?: string;
  /** Reports whether any field differs from `initial` — drives a host `FormDialogShell`'s discard-confirm. */
  onDirtyChange?: (dirty: boolean) => void;
}

interface PatientFormValues {
  firstName: string;
  lastName: string;
  age: string;
  gender: Gender | null;
  conditions: string[];
  relation: Relation | null;
}

/**
 * The A4 patient form — first/last name, age, **required** gender, optional condition chips, and
 * (for E1) the relation. Reused for create and edit. Gender is required and never defaulted; age
 * maps to `birthDate` (never rendered back as a fabricated full date — display stays age-only).
 * `lastName` falls back to `firstName` only when left blank (the wire's `lastName` is required),
 * never guessed by splitting a single field. Strings come from the `onboarding` namespace.
 *
 * react-hook-form owns the values, which is what lets `onDirtyChange` report `formState.isDirty`
 * instead of the hand-written six-way comparison against captured initial values it used to run in an
 * effect on every keystroke.
 * @component PatientForm
 */
const PatientForm: FunctionComponent<PatientFormProps> = ({
  initial,
  showRelation = false,
  submitLabel,
  submitting = false,
  onSubmit,
  onCancel,
  cancelLabel,
  onDirtyChange,
}) => {
  const t = useTranslations('onboarding');

  const initialAge = birthDateToAge(initial?.birthDate);

  const form = useForm<PatientFormValues>({
    mode: 'onTouched',
    defaultValues: {
      firstName: initial?.firstName ?? '',
      lastName: initial?.lastName ?? '',
      age: initialAge == null ? '' : String(initialAge),
      gender: initial?.gender ?? null,
      conditions: initial?.conditions ?? [],
      relation: initial?.relation ?? null,
    },
  });
  const { handleSubmit, formState } = form;
  const { isDirty } = formState;

  useEffect(() => {
    onDirtyChange?.(isDirty);
  }, [isDirty, onDirtyChange]);

  const submit = (values: PatientFormValues) => {
    const first = values.firstName.trim();
    const enteredLast = values.lastName.trim();
    // The wire's `lastName` is a required string, so it falls back to the first name when left
    // blank — but `displayName` reflects only what was actually entered (never a duplicated name).
    onSubmit({
      displayName: [first, enteredLast].filter(Boolean).join(' '),
      firstName: first,
      lastName: enteredLast || first,
      birthDate: ageToBirthDate(Number(digitsOnly(values.age))),
      gender: values.gender as Gender,
      bloodType: null,
      initialMedicalNotes: null,
      relation: values.relation,
      conditions: values.conditions as ConditionCode[],
    });
  };

  return (
    <FormProvider {...form}>
      <Stack component="form" noValidate onSubmit={handleSubmit(submit)} sx={{ gap: 2.5 }}>
        <Stack direction={{ xs: 'column', sm: 'row' }} sx={{ gap: 2 }}>
          <RhfTextField<PatientFormValues>
            name="firstName"
            label={t('first_name_label')}
            rules={{ validate: (value) => String(value ?? '').trim().length > 0 || t('name_required') }}
            fullWidth
          />
          <RhfTextField<PatientFormValues> name="lastName" label={t('last_name_label')} fullWidth />
        </Stack>

        <RhfTextField<PatientFormValues>
          name="age"
          label={t('age_label')}
          transform={(raw) => digitsOnly(raw).slice(0, MAX_AGE_DIGITS)}
          rules={{
            validate: (value) => {
              const raw = String(value ?? '').trim();
              const parsed = Number(digitsOnly(raw));
              return (raw.length > 0 && Number.isInteger(parsed) && parsed >= 0 && parsed <= MAX_AGE) || t('age_invalid');
            },
          }}
          slotProps={{ htmlInput: { dir: 'ltr', inputMode: 'numeric', style: { textAlign: 'start' } } }}
          sx={{ maxWidth: 160 }}
        />

        <RhfControlGroup<PatientFormValues>
          name="gender"
          label={t('gender_label')}
          rules={{ validate: (value) => value != null || t('gender_required') }}
        >
          {({ field, hasError }) => (
            <GenderToggle
              value={field.value as Gender | null}
              onChange={field.onChange}
              maleLabel={t('gender_male')}
              femaleLabel={t('gender_female')}
              error={hasError}
              ariaLabel={t('gender_label')}
            />
          )}
        </RhfControlGroup>

        <RhfChipSelect<PatientFormValues>
          name="conditions"
          label={t('conditions_label')}
          hint={t('conditions_hint')}
          options={CONDITION_CODES.map((code) => ({ code, label: t(`condition_${code}`) }))}
        />

        {showRelation ? (
          <RhfControlGroup<PatientFormValues> name="relation" label={t('relation_title')}>
            {({ field }) => (
              <RelationSelect
                options={RELATION_CODES.map((code) => ({ code, label: t(`relation_${code}`) }))}
                value={field.value as Relation | null}
                onChange={(code) => field.onChange(code as Relation)}
              />
            )}
          </RhfControlGroup>
        ) : null}

        <Stack direction="row" sx={{ gap: 1, justifyContent: 'flex-end' }}>
          {onCancel ? (
            <AppButton variant="text" onClick={onCancel} disabled={submitting}>
              {cancelLabel}
            </AppButton>
          ) : null}
          <AppButton type="submit" color="primary" variant="contained" disabled={submitting}>
            {submitLabel}
          </AppButton>
        </Stack>
      </Stack>
    </FormProvider>
  );
};

export default PatientForm;
