import { useCallback, useMemo } from 'react';
import { Select, SimpleGrid, Text, TextInput } from '@mantine/core';
import type { FieldErrors, UseFormRegister, UseFormSetValue, UseFormWatch, UseFormTrigger } from 'react-hook-form';
import { z } from 'zod';
import type { TFunction } from 'i18next';
import { useTranslation } from 'react-i18next';
import { phoneNumber, optionalPhoneNumber, CountrySelect, PhoneInput } from '@ema-platform/ui';
import { LocationPicker } from '../../location/components/LocationPicker';
import { useGetLocationTypesQuery } from '../../location/api/location-api';
import type { Location, LocationType } from '../../location/types/location';

// Zod schemas can't call hooks, so the schema is built from `t` by the
// caller (ProfilePage) rather than defined once at module scope.
export function addressSchema(t: TFunction) {
  return z.object({
    idType: z.string().min(1, t('profileAddress.validation.idTypeRequired')),
    idNumber: z.string().trim().min(1, t('profileAddress.validation.idNumberRequired')),
    // Alpha-2 country code from CountrySelect; converted to a full name at submit.
    nationality: z.string().min(1, t('profileAddress.validation.nationalityRequired')),
    primaryPhoneNumber: phoneNumber,
    secondaryPhoneNumber: optionalPhoneNumber,
    email: z.string().trim().email(t('profileAddress.validation.emailInvalid')).optional().or(z.literal('')),
    regionId: z.string().optional(),
    cityId: z.string().optional(),
    subCityId: z.string().optional(),
    woredaId: z.string().optional(),
    kebeleId: z.string().optional(),
    streetAddress: z.string().trim().optional(),
    postalAddress: z.string().trim().optional(),
    // Emergency contact is collected but never required — leaving it blank must
    // not stop an applicant moving on.
    emergencyContactName: z.string().trim().optional(),
    emergencyContactPhone: optionalPhoneNumber,
    emergencyContactRelation: z.string().trim().optional(),
  });
}

export type AddressValues = z.infer<ReturnType<typeof addressSchema>>;

// Backend rejects anything outside this set:
// "idType must be one of the following values: NID, VITAL, PASSPORT, DRIVERS_LICENSE"
function idTypeOptions(t: TFunction) {
  return [
    { value: 'NID', label: t('profileAddress.idTypeOptions.NID') },
    { value: 'VITAL', label: t('profileAddress.idTypeOptions.VITAL') },
    { value: 'PASSPORT', label: t('profileAddress.idTypeOptions.PASSPORT') },
    { value: 'DRIVERS_LICENSE', label: t('profileAddress.idTypeOptions.DRIVERS_LICENSE') },
  ] as const;
}

/**
 * Location types are data-driven rows (no fixed depth), so the chain is
 * mapped to a field by type *code* rather than by numeric level — this
 * resolves correctly whether or not a COUNTRY type sits above REGION.
 */
function fieldsForLocationType(type: LocationType): Array<keyof AddressValues> {
  // Location types have historically used variants such as SUBCITY,
  // SUB_CITY, and SUB-CITY. Normalize both the code and display name so a
  // selected sub-city is never dropped from the address payload.
  const typeName = `${type.code} ${type.names.en}`
    .toUpperCase()
    .replace(/[^A-Z0-9]/g, '');

  if (typeName.includes('SUBCITY')) return ['subCityId'];
  if (typeName.includes('WOREDA')) return ['woredaId'];
  if (typeName.includes('REGION')) return ['regionId'];
  if (typeName.includes('CITY')) {
    // The profile-completeness API treats the selected City as its region.
    // Keep its conventional cityId too, as other profile consumers use it.
    return ['regionId', 'cityId'];
  }
  return [];
}

interface AddressFormContentProps {
  register: UseFormRegister<AddressValues>;
  errors: FieldErrors<AddressValues>;
  setValue: UseFormSetValue<AddressValues>;
  watch: UseFormWatch<AddressValues>;
  trigger: UseFormTrigger<AddressValues>;
}

export function AddressFormContent({
  register,
  errors,
  setValue,
  watch,
  trigger,
}: AddressFormContentProps) {
  const { t } = useTranslation();
  const { data: typesRes } = useGetLocationTypesQuery();
  const locationTypes = typesRes?.items;

  const typeFieldMap = useMemo(() => {
    const map = new Map<string, Array<keyof AddressValues>>();
    locationTypes?.forEach((lt) => {
      const fields = fieldsForLocationType(lt);
      if (fields.length) map.set(lt.id, fields);
    });
    return map;
  }, [locationTypes]);

  const leafId = watch('woredaId') || watch('subCityId') || watch('cityId') || watch('regionId') || undefined;

  const handleChainChange = useCallback(
    (chain: Location[]) => {
      setValue('regionId', '');
      setValue('cityId', '');
      setValue('subCityId', '');
      setValue('woredaId', '');

      chain.forEach((loc) => {
        typeFieldMap.get(loc.locationTypeId)?.forEach((field) => {
          setValue(field, loc.id);
        });
      });
    },
    [setValue, typeFieldMap],
  );

  return (
    <>
      <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
        <Select
          label={t('profileFields.idType')}
          placeholder={t('profileAddress.idTypePlaceholder')}
          required
          data={idTypeOptions(t)}
          error={errors.idType?.message}
          value={watch('idType')}
          onChange={(val) => setValue('idType', val || '', { shouldValidate: true })}
          onBlur={() => trigger('idType')}
          name="idType"
        />
        <TextInput
          label={t('profileFields.idNumber')}
          placeholder={t('profileAddress.idNumberPlaceholder')}
          required
          {...register('idNumber')}
          error={errors.idNumber?.message}
        />
        <CountrySelect
          label={t('profileFields.nationality')}
          demonym
          required
          value={watch('nationality') || null}
          onChange={(val) => setValue('nationality', val || '', { shouldValidate: true })}
          error={errors.nationality?.message}
        />
        <PhoneInput
          label={t('profileFields.primaryPhoneNumber')}
          description={t('profileAddress.accountManagedHint')}
          required
          readOnly
          value={watch('primaryPhoneNumber') || ''}
          onChange={(val) => setValue('primaryPhoneNumber', val, { shouldValidate: !!errors.primaryPhoneNumber })}
          onBlur={() => trigger('primaryPhoneNumber')}
          error={errors.primaryPhoneNumber?.message}
        />
        <PhoneInput
          label={t('profileAddress.secondaryPhoneNumber')}
          placeholder={t('profileAddress.phonePlaceholder')}
          value={watch('secondaryPhoneNumber') || ''}
          onChange={(val) => setValue('secondaryPhoneNumber', val, { shouldValidate: !!errors.secondaryPhoneNumber })}
          onBlur={() => trigger('secondaryPhoneNumber')}
          error={errors.secondaryPhoneNumber?.message}
        />
        <TextInput
          label={t('profileFields.email')}
          type="email"
          description={t('profileAddress.accountManagedHint')}
          readOnly
          {...register('email')}
          error={errors.email?.message}
        />
      </SimpleGrid>

      <Text fw={600} fz="sm" tt="uppercase" c="gray.6" mt="lg" mb="sm">
        {t('profileAddress.addressSection')}
      </Text>
      {/* City / Sub-city / Woreda — the picker's depth. Kebele is a seeded
          level but nothing collects it, so `kebeleId` stays unset rather than
          borrowing the woreda's id. */}
      <LocationPicker value={leafId} onChainChange={handleChainChange} maxDepth={3} />
      <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md" mt="md">
        <TextInput
          label={t('profileFields.streetAddress')}
          placeholder={t('profileAddress.streetAddressPlaceholder')}
          {...register('streetAddress')}
          error={errors.streetAddress?.message}
        />
        <TextInput
          label={t('profileAddress.postalAddress')}
          placeholder={t('profileAddress.postalAddressPlaceholder')}
          {...register('postalAddress')}
          error={errors.postalAddress?.message}
        />
      </SimpleGrid>

      <Text fw={600} fz="sm" tt="uppercase" c="gray.6" mt="lg" mb="sm">
        {t('profileAddress.emergencyContactSection')}{' '}
        <Text span c="dimmed" fz="xs" tt="none" fw={400}>
          {t('profileAddress.emergencyContactOptional')}
        </Text>
      </Text>
      <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
        <TextInput
          label={t('profileAddress.contactName')}
          placeholder={t('profileAddress.contactNamePlaceholder')}
          {...register('emergencyContactName')}
          error={errors.emergencyContactName?.message}
        />
        <PhoneInput
          label={t('profileAddress.contactPhone')}
          placeholder={t('profileAddress.phonePlaceholder')}
          value={watch('emergencyContactPhone') || ''}
          onChange={(val) => setValue('emergencyContactPhone', val, { shouldValidate: !!errors.emergencyContactPhone })}
          onBlur={() => trigger('emergencyContactPhone')}
          error={errors.emergencyContactPhone?.message}
        />
        <TextInput
          label={t('profileAddress.relationship')}
          placeholder={t('profileAddress.relationshipPlaceholder')}
          {...register('emergencyContactRelation')}
          error={errors.emergencyContactRelation?.message}
        />
      </SimpleGrid>
    </>
  );
}
