'use client';
import { FunctionComponent } from 'react';
import { useLocale, useTranslations } from 'next-intl';
import CircularProgress from '@mui/material/CircularProgress';
import InputAdornment from '@mui/material/InputAdornment';
import MenuItem from '@mui/material/MenuItem';
import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField';
import { useProvinces, useCities, useDistricts } from '@/services/geography';
import { pickRegionName } from '@/services/geography/names';

/** The region a caller reads back — a `null` id means "not chosen yet"; a `null` district also
 * doubles as the deliberate "whole city" choice once a city is set. */
export interface CascadingRegionValue {
  provinceId: number | null;
  cityId: number | null;
  districtId: number | null;
}

export interface CascadingRegionSelectProps {
  value: CascadingRegionValue;
  onChange: (next: CascadingRegionValue) => void;
  /** Render the district level. Off for a whole-city-only context (e.g. the coverage "whole city" scope). */
  includeDistrict?: boolean;
  cityError?: boolean;
  cityErrorText?: string;
  districtError?: boolean;
  districtErrorText?: string;
  disabled?: boolean;
}

const toId = (raw: string): number | null => (raw === '' ? null : Number(raw));

/**
 * Province → city → district cascading dropdowns, driving the aggressively-cached geography
 * queries itself so both the address form and the coverage editor drop it in with only a
 * `value`/`onChange`. Each level enables only once its parent is chosen and resets its children
 * on change; inactive regions never arrive (the server filters them), and a city with no
 * districts surfaces the **whole-city** affordance rather than an error. **City is required;
 * district is optional** — leaving district empty is a real choice, never an error.
 * @component CascadingRegionSelect
 */
const CascadingRegionSelect: FunctionComponent<CascadingRegionSelectProps> = ({
  value,
  onChange,
  includeDistrict = true,
  cityError = false,
  cityErrorText,
  districtError = false,
  districtErrorText,
  disabled = false,
}) => {
  const t = useTranslations('geo');
  const locale = useLocale();

  const provincesQuery = useProvinces();
  const citiesQuery = useCities(value.provinceId);
  const districtsQuery = useDistricts(value.cityId);

  const provinces = provincesQuery.data ?? [];
  const cities = citiesQuery.data ?? [];
  const districts = districtsQuery.data ?? [];

  const hasProvince = value.provinceId != null;
  const hasCity = value.cityId != null;
  // Distinguish "not fetched yet" from "fetched and genuinely empty" (whole-city-only city).
  const cityHasNoDistricts = hasCity && districtsQuery.isSuccess && districts.length === 0;

  // Only bind a value the loaded options actually contain — an id whose options are still
  // fetching (e.g. an edit prefill) would otherwise trip MUI's out-of-range Select warning.
  const provinceValue = provinces.some((province) => province.id === value.provinceId) ? value.provinceId : '';
  const cityValue = cities.some((city) => city.id === value.cityId) ? value.cityId : '';
  const districtValue = districts.some((district) => district.id === value.districtId) ? value.districtId : '';

  const loadingAdornment = (loading: boolean) =>
    loading
      ? {
          endAdornment: (
            <InputAdornment position="end">
              <CircularProgress size={16} />
            </InputAdornment>
          ),
        }
      : undefined;

  const handleProvince = (raw: string) =>
    onChange({ provinceId: toId(raw), cityId: null, districtId: null });

  const handleCity = (raw: string) =>
    onChange({ provinceId: value.provinceId, cityId: toId(raw), districtId: null });

  const handleDistrict = (raw: string) =>
    onChange({ provinceId: value.provinceId, cityId: value.cityId, districtId: toId(raw) });

  return (
    <Stack sx={{ gap: 2 }}>
      <TextField
        select
        label={t('province')}
        value={provinceValue}
        onChange={(event) => handleProvince(event.target.value)}
        disabled={disabled || provincesQuery.isLoading}
        slotProps={{ input: loadingAdornment(provincesQuery.isLoading) }}
        fullWidth
      >
        {provinces.map((province) => (
          <MenuItem key={province.id} value={province.id}>
            {pickRegionName(province, locale)}
          </MenuItem>
        ))}
      </TextField>

      <TextField
        select
        label={t('city')}
        value={cityValue}
        onChange={(event) => handleCity(event.target.value)}
        disabled={disabled || !hasProvince || citiesQuery.isLoading}
        error={cityError}
        helperText={cityError ? cityErrorText : !hasProvince ? t('city_needs_province') : undefined}
        slotProps={{ input: loadingAdornment(citiesQuery.isLoading) }}
        fullWidth
      >
        {cities.map((city) => (
          <MenuItem key={city.id} value={city.id}>
            {pickRegionName(city, locale)}
          </MenuItem>
        ))}
      </TextField>

      {includeDistrict ? (
        <TextField
          select
          label={t('district')}
          value={districtValue}
          onChange={(event) => handleDistrict(event.target.value)}
          disabled={disabled || !hasCity || districtsQuery.isLoading || cityHasNoDistricts}
          error={districtError}
          helperText={
            districtError
              ? districtErrorText
              : !hasCity
                ? t('district_needs_city')
                : cityHasNoDistricts
                  ? t('no_districts')
                  : t('district_optional')
          }
          slotProps={{ input: loadingAdornment(districtsQuery.isLoading) }}
          fullWidth
        >
          {/* The empty option is the explicit "whole city" choice — district is optional. */}
          <MenuItem value="">{t('whole_city')}</MenuItem>
          {districts.map((district) => (
            <MenuItem key={district.id} value={district.id}>
              {pickRegionName(district, locale)}
            </MenuItem>
          ))}
        </TextField>
      ) : null}
    </Stack>
  );
};

export default CascadingRegionSelect;
