'use client';
import { FunctionComponent, useEffect } from 'react';
import { useTranslations } from 'next-intl';
import { FormProvider, useForm, useWatch } from 'react-hook-form';
import FormControlLabel from '@mui/material/FormControlLabel';
import Stack from '@mui/material/Stack';
import Switch from '@mui/material/Switch';
import { AppButton } from '@/components/common';
import { RhfControlGroup, RhfTextField } from '@/components/common/form';
import { cityCentroid } from '@/services/geography/constants';
import type { CreateAddressInput, LatLng } from '@/services/addresses/types';
import CascadingRegionSelect, { type CascadingRegionValue } from './CascadingRegionSelect';
import AddressMapPicker from './AddressMapPicker';

/** Prefill for edit (or empty for add). `provinceId` is needed to prefill the cascade. */
export interface AddressFormInitial {
  title?: string;
  provinceId?: number | null;
  cityId?: number | null;
  districtId?: number | null;
  addressLine?: string | null;
  latitude?: number | null;
  longitude?: number | null;
  isPrimary?: boolean;
}

export interface AddressFormProps {
  initial?: AddressFormInitial;
  submitting?: boolean;
  onSubmit: (input: CreateAddressInput) => void;
  onCancel?: () => void;
  /** Reports whether any field differs from `initial` — drives a host `FormDialogShell`'s discard-confirm. */
  onDirtyChange?: (dirty: boolean) => void;
}

interface AddressFormValues {
  title: string;
  region: CascadingRegionValue;
  pin: LatLng | null;
  addressLine: string;
  isPrimary: boolean;
}

// Only prefill the region when we have the province — a city id without its province can't drive
// the (per-province) city query, so the cascade starts fresh instead of showing a dead value.
function initialRegion(initial?: AddressFormInitial): CascadingRegionValue {
  if (initial?.provinceId == null) return { provinceId: null, cityId: null, districtId: null };
  return { provinceId: initial.provinceId, cityId: initial.cityId ?? null, districtId: initial.districtId ?? null };
}

function initialPin(initial?: AddressFormInitial): LatLng | null {
  return initial?.latitude != null && initial?.longitude != null
    ? { latitude: initial.latitude, longitude: initial.longitude }
    : null;
}

/**
 * The add/edit address form body — the cascading region dropdowns + the map-pin picker + a
 * title and street address + a "set as primary" toggle. Validation: **city required**, **pin
 * required** (surfaced inline), title + street required, **district optional**. Emits a
 * `CreateAddressInput` carrying the picked coordinates. Reused for create and edit.
 *
 * The region cascade and the map pin are composite values (`{province, city, district}` and a
 * lat/lng pair), which is exactly why they belong in form state rather than beside it: as
 * react-hook-form fields they carry their own required-rule and their own error, instead of the four
 * parallel `xxxError` booleans the submit handler used to set by hand.
 * @component AddressForm
 */
const AddressForm: FunctionComponent<AddressFormProps> = ({ initial, submitting = false, onSubmit, onCancel, onDirtyChange }) => {
  const t = useTranslations('address');
  const tc = useTranslations('common');

  const form = useForm<AddressFormValues>({
    mode: 'onTouched',
    defaultValues: {
      title: initial?.title ?? '',
      region: initialRegion(initial),
      pin: initialPin(initial),
      addressLine: initial?.addressLine ?? '',
      isPrimary: initial?.isPrimary ?? false,
    },
  });
  const { control, handleSubmit, formState } = form;
  const { isDirty } = formState;
  const region = useWatch({ control, name: 'region' });

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

  const submit = (values: AddressFormValues) => {
    onSubmit({
      title: values.title.trim(),
      provinceId: values.region.provinceId as number,
      cityId: values.region.cityId as number,
      districtId: values.region.districtId,
      addressLine: values.addressLine.trim(),
      latitude: (values.pin as LatLng).latitude,
      longitude: (values.pin as LatLng).longitude,
      isPrimary: values.isPrimary,
    });
  };

  return (
    <FormProvider {...form}>
      <Stack component="form" noValidate onSubmit={handleSubmit(submit)} sx={{ gap: 2.5 }}>
        <RhfTextField<AddressFormValues>
          name="title"
          label={t('title_label')}
          placeholder={t('title_placeholder')}
          rules={{ validate: (value) => String(value ?? '').trim().length > 0 || t('title_required') }}
          fullWidth
        />

        {/* Message-less rules on purpose: both controls below already render their own error copy, so
            `RhfControlGroup` must flag the field without printing a second identical line. */}
        <RhfControlGroup<AddressFormValues>
          name="region"
          rules={{ validate: (value) => (value as CascadingRegionValue)?.cityId != null }}
        >
          {({ field, hasError }) => (
            <CascadingRegionSelect
              value={field.value as CascadingRegionValue}
              onChange={field.onChange}
              cityError={hasError}
              cityErrorText={t('city_required')}
            />
          )}
        </RhfControlGroup>

        <RhfControlGroup<AddressFormValues> name="pin" rules={{ validate: (value) => value != null }}>
          {({ field, hasError }) => (
            <AddressMapPicker
              value={field.value as LatLng | null}
              onChange={field.onChange}
              center={cityCentroid(region.cityId)}
              helperText={t('map_hint')}
              latLabel={t('map_lat')}
              lngLabel={t('map_lng')}
              error={hasError}
              errorText={t('map_required')}
            />
          )}
        </RhfControlGroup>

        <RhfTextField<AddressFormValues>
          name="addressLine"
          label={t('line_label')}
          helperText={t('line_hint')}
          rules={{ validate: (value) => String(value ?? '').trim().length > 0 || t('line_required') }}
          multiline
          minRows={2}
          fullWidth
        />

        <RhfControlGroup<AddressFormValues> name="isPrimary">
          {({ field }) => (
            <FormControlLabel
              control={<Switch checked={Boolean(field.value)} onChange={(event) => field.onChange(event.target.checked)} />}
              label={t('set_primary_toggle')}
            />
          )}
        </RhfControlGroup>

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

export default AddressForm;
