import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Group, Select, Text, type ComboboxItem, type SelectProps } from '@mantine/core';
import { registerLocale, getNames, getName, getAlpha2Code } from 'i18n-iso-countries';
import {
  registerLocale as registerNationalityLocale,
  getName as getNationalityNameRaw,
} from 'i18n-nationality';
import * as Flags from 'country-flag-icons/react/3x2';
import en from 'i18n-iso-countries/langs/en.json';
import am from 'i18n-iso-countries/langs/am.json';
import nationalityEn from 'i18n-nationality/langs/en.json';

// Registered once at module load — locale data is static.
registerLocale(en);
registerLocale(am);
registerNationalityLocale(nationalityEn);

export type CountryLang = 'en' | 'am';

export function resolveLang(lng: string): CountryLang {
  return lng === 'am' ? 'am' : 'en';
}

/** Localized country name for an alpha-2 code; '' when unset/unknown. */
export function getCountryName(code: string | null | undefined, lang: CountryLang = 'en'): string {
  return code ? (getName(code, lang) ?? '') : '';
}

/** Alpha-2 code for a stored country name (e.g. "Ethiopian" data); undefined when unmatched. */
export function getCountryCode(name: string | null | undefined, lang: CountryLang = 'en'): string | undefined {
  return name ? getAlpha2Code(name, lang) : undefined;
}

/**
 * Localized demonym for an alpha-2 code (e.g. "ET" -> "Ethiopian"), for
 * nationality fields as opposed to plain country fields.
 * ponytail: i18n-nationality only ships an English locale — Amharic falls
 * back to the country name until an Amharic demonym dataset shows up.
 */
export function getNationalityName(code: string | null | undefined, lang: CountryLang = 'en'): string {
  if (!code) return '';
  if (lang === 'en') return getNationalityNameRaw(code, 'en') ?? getCountryName(code, lang);
  return getCountryName(code, lang);
}

export function CountryFlag({ code }: { code: string }) {
  const Flag = Flags[code as keyof typeof Flags];
  return Flag ? <Flag style={{ width: 22, borderRadius: 2, display: 'block' }} /> : null;
}

// Case-insensitive substring on name, plus ISO code prefix ("et" → Ethiopia).
const filterCountries: SelectProps['filter'] = ({ options, search }) => {
  const q = search.trim().toLowerCase();
  if (!q) return options;
  return (options as ComboboxItem[]).filter(
    (o) => o.label.toLowerCase().includes(q) || o.value.toLowerCase().startsWith(q),
  );
};

// Module scope → stable reference, no re-render churn.
const renderCountryOption: SelectProps['renderOption'] = ({ option }) => (
  <Group gap="xs" wrap="nowrap">
    <CountryFlag code={option.value} />
    <Text fz="sm">{option.label}</Text>
  </Group>
);

export interface CountrySelectProps {
  value: string | null;
  onChange: (value: string | null) => void;
  label?: string;
  placeholder?: string;
  description?: React.ReactNode;
  error?: React.ReactNode;
  required?: boolean;
  disabled?: boolean;
  /** Show nationality labels ("Ethiopian") instead of country names ("Ethiopia"). */
  demonym?: boolean;
}

export function CountrySelect({
  value,
  onChange,
  placeholder,
  demonym,
  ...rest
}: CountrySelectProps) {
  const { t, i18n } = useTranslation();
  const lang = resolveLang(i18n.language);

  const countries = useMemo(
    () =>
      Object.keys(getNames(lang))
        .map((code) => ({ value: code, label: demonym ? getNationalityName(code, lang) : getCountryName(code, lang) }))
        .sort((a, b) => a.label.localeCompare(b.label, lang)),
    [lang, demonym],
  );

  return (
    <Select
      data={countries}
      value={value}
      onChange={onChange}
      placeholder={placeholder ?? t('country.select')}
      leftSection={value ? <CountryFlag code={value} /> : undefined}
      renderOption={renderCountryOption}
      filter={filterCountries}
      nothingFoundMessage={t('country.notFound')}
      searchable
      clearable
      maxDropdownHeight={320}
      {...rest}
    />
  );
}
