import { cn } from "@/lib/utils";
import {
  useState,
  useCallback,
  forwardRef,
  type ChangeEvent,
  type FocusEvent,
} from "react";
import { ChevronDown, Phone, Check, X } from "lucide-react";

// ============================================
// TYPES & INTERFACES
// ============================================

export interface CountryPhone {
  code: string; // Code pays (ex: "FR", "MG")
  name: string; // Nom du pays
  dialCode: string; // Indicatif (ex: "+33", "+261")
  flag: string; // Emoji drapeau
  format: string; // Format d'affichage (ex: "+33 6 XX XX XX XX")
  placeholder: string; // Placeholder
  regex: RegExp; // Validation regex
  maxLength: number; // Longueur maximale
  formatter: (value: string) => string; // Fonction de formatage
}

export interface ValidationResult {
  isValid: boolean;
  message?: string;
}

export interface InternationalPhoneInputProps {
  label?: string;
  required?: boolean;
  error?: string;
  className?: string;
  containerClassName?: string;
  onValueChange?: (value: string, isValid: boolean, country: CountryPhone) => void;
  onChange?: (value: string) => void;
  value?: string;
  name?: string;
  disabled?: boolean;
  placeholder?: string;
  id?: string;
  onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
  defaultCountry?: string; // Code pays par défaut (ex: "FR")
  showValidation?: boolean;
}

// ============================================
// CONFIGURATION DES PAYS
// ============================================

export const COUNTRY_PHONES: CountryPhone[] = [
  {
    code: "FR",
    name: "France",
    dialCode: "+33",
    flag: "🇫🇷",
    format: "+33 X XX XX XX XX",
    placeholder: "6 12 34 56 78",
    regex: /^[1-9]\d{8}$/,
    maxLength: 9,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      const match = cleaned.match(/^(\d{0,1})(\d{0,2})(\d{0,2})(\d{0,2})(\d{0,2})$/);
      if (!match) return cleaned;
      
      const parts = [match[1], match[2], match[3], match[4], match[5]].filter(Boolean);
      return parts.join(" ");
    },
  },
  {
    code: "MG",
    name: "Madagascar",
    dialCode: "+261",
    flag: "🇲🇬",
    format: "+261 XX XX XXX XX",
    placeholder: "33 12 345 67",
    regex: /^3[2-4]\d{7}$/,
    maxLength: 9,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      const match = cleaned.match(/^(\d{0,2})(\d{0,2})(\d{0,3})(\d{0,2})$/);
      if (!match) return cleaned;
      
      const parts = [match[1], match[2], match[3], match[4]].filter(Boolean);
      return parts.join(" ");
    },
  },
  {
    code: "US",
    name: "États-Unis",
    dialCode: "+1",
    flag: "🇺🇸",
    format: "+1 (XXX) XXX-XXXX",
    placeholder: "(555) 123-4567",
    regex: /^[2-9]\d{2}[2-9]\d{6}$/,
    maxLength: 10,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 10)
        .replace(/(\d{3})(\d{3})?(\d{4})?/, (_, p1, p2, p3) => {
          if (p3) return `(${p1}) ${p2}-${p3}`;
          if (p2) return `(${p1}) ${p2}`;
          return `(${p1}`;
        });
    },
  },
  {
    code: "GB",
    name: "Royaume-Uni",
    dialCode: "+44",
    flag: "🇬🇧",
    format: "+44 XXXX XXX XXX",
    placeholder: "7400 123 456",
    regex: /^7\d{9}$/,
    maxLength: 10,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 10)
        .replace(/(\d{4})(\d{3})?(\d{3})?/, (_, p1, p2, p3) =>
          [p1, p2, p3].filter(Boolean).join(" ")
        );
    },
  },
  {
    code: "DE",
    name: "Allemagne",
    dialCode: "+49",
    flag: "🇩🇪",
    format: "+49 XXX XXXXXXX",
    placeholder: "151 12345678",
    regex: /^1[5-7]\d{8,9}$/,
    maxLength: 11,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 11)
        .replace(/(\d{3})(\d{4})?(\d{4})?/, (_, p1, p2, p3) =>
          [p1, p2, p3].filter(Boolean).join(" ")
        );
    },
  },
  {
    code: "ES",
    name: "Espagne",
    dialCode: "+34",
    flag: "🇪🇸",
    format: "+34 XXX XX XX XX",
    placeholder: "612 34 56 78",
    regex: /^[6-7]\d{8}$/,
    maxLength: 9,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 9)
        .replace(/(\d{3})(\d{2})?(\d{2})?(\d{2})?/, (_, p1, p2, p3, p4) =>
          [p1, p2, p3, p4].filter(Boolean).join(" ")
        );
    },
  },
  {
    code: "IT",
    name: "Italie",
    dialCode: "+39",
    flag: "🇮🇹",
    format: "+39 XXX XXX XXXX",
    placeholder: "312 345 6789",
    regex: /^3\d{8,9}$/,
    maxLength: 10,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 10)
        .replace(/(\d{3})(\d{3})?(\d{4})?/, (_, p1, p2, p3) =>
          [p1, p2, p3].filter(Boolean).join(" ")
        );
    },
  },
  {
    code: "BE",
    name: "Belgique",
    dialCode: "+32",
    flag: "🇧🇪",
    format: "+32 XXX XX XX XX",
    placeholder: "470 12 34 56",
    regex: /^4[5-9]\d{7}$/,
    maxLength: 9,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 9)
        .replace(/(\d{3})(\d{2})?(\d{2})?(\d{2})?/, (_, p1, p2, p3, p4) =>
          [p1, p2, p3, p4].filter(Boolean).join(" ")
        );
    },
  },
  {
    code: "CH",
    name: "Suisse",
    dialCode: "+41",
    flag: "🇨🇭",
    format: "+41 XX XXX XX XX",
    placeholder: "79 123 45 67",
    regex: /^7[5-9]\d{7}$/,
    maxLength: 9,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 9)
        .replace(/(\d{2})(\d{3})?(\d{2})?(\d{2})?/, (_, p1, p2, p3, p4) =>
          [p1, p2, p3, p4].filter(Boolean).join(" ")
        );
    },
  },
  {
    code: "CA",
    name: "Canada",
    dialCode: "+1",
    flag: "🇨🇦",
    format: "+1 (XXX) XXX-XXXX",
    placeholder: "(514) 123-4567",
    regex: /^[2-9]\d{2}[2-9]\d{6}$/,
    maxLength: 10,
    formatter: (value: string) => {
      const cleaned = value.replace(/\D/g, "");
      return cleaned
        .slice(0, 10)
        .replace(/(\d{3})(\d{3})?(\d{4})?/, (_, p1, p2, p3) => {
          if (p3) return `(${p1}) ${p2}-${p3}`;
          if (p2) return `(${p1}) ${p2}`;
          return `(${p1}`;
        });
    },
  },
];

// ============================================
// COMPOSANT PRINCIPAL
// ============================================

export const InternationalPhoneInput = forwardRef<
  HTMLInputElement,
  InternationalPhoneInputProps
>((props, ref) => {
  const {
    label = "Téléphone",
    required = false,
    error: externalError,
    className = "",
    containerClassName = "",
    onValueChange,
    onChange,
    value: controlledValue,
    name,
    disabled,
    placeholder,
    id,
    onBlur: onBlurProp,
    defaultCountry = "FR",
    showValidation = true,
  } = props;

  // États
  const [selectedCountry, setSelectedCountry] = useState<CountryPhone>(
    COUNTRY_PHONES.find((c) => c.code === defaultCountry) || COUNTRY_PHONES[0]
  );
  const [internalValue, setInternalValue] = useState<string>("");
  const [touched, setTouched] = useState<boolean>(false);
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
  const [validationResult, setValidationResult] = useState<ValidationResult>({
    isValid: true,
  });

  // Extraire le numéro local depuis le numéro complet
  const extractLocalNumber = useCallback((fullNumber: string): string => {
    if (!fullNumber) return "";
    
    // Enlever l'indicatif du pays s'il est présent
    const withoutDialCode = fullNumber.replace(selectedCountry.dialCode, "").trim();
    return withoutDialCode;
  }, [selectedCountry]);

  // Valeur locale (sans l'indicatif)
  const localValue = controlledValue !== undefined 
    ? extractLocalNumber(String(controlledValue))
    : internalValue;

  // Validation
  const validate = useCallback(
    (val: string, country: CountryPhone): ValidationResult => {
      if (!val && !required) {
        return { isValid: true };
      }
      if (!val && required) {
        return { isValid: false, message: "Ce champ est requis" };
      }

      const cleaned = val.replace(/\D/g, "");
      
      if (!country.regex.test(cleaned)) {
        return {
          isValid: false,
          message: `Format ${country.name} invalide (ex: ${country.placeholder})`,
        };
      }

      return { isValid: true };
    },
    [required]
  );

  // Gestion du changement
  const handleChange = useCallback(
    (e: ChangeEvent<HTMLInputElement>): void => {
      const rawValue = e.target.value;
      
      // Ne garder que les chiffres et espaces
      const cleanedValue = rawValue.replace(/[^\d\s]/g, "");
      
      // Formater selon le pays sélectionné
      const formattedValue = selectedCountry.formatter(cleanedValue);

      // Mise à jour de la valeur interne si non contrôlé
      if (controlledValue === undefined) {
        setInternalValue(formattedValue);
      }

      // Validation
      const result = validate(formattedValue, selectedCountry);
      setValidationResult(result);

      // Callbacks - Envoyer le numéro complet
      const fullNumber = formattedValue ? `${selectedCountry.dialCode} ${formattedValue}` : "";
      onValueChange?.(fullNumber, result.isValid, selectedCountry);
      onChange?.(fullNumber);
    },
    [controlledValue, selectedCountry, validate, onValueChange, onChange]
  );

  // Gestion du blur
  const handleBlur = useCallback(
    (e: FocusEvent<HTMLInputElement>): void => {
      setTouched(true);
      const result = validate(localValue, selectedCountry);
      setValidationResult(result);
      onBlurProp?.(e);
    },
    [onBlurProp, validate, localValue, selectedCountry]
  );

  // Changer de pays
  const handleCountryChange = useCallback(
    (country: CountryPhone) => {
      setSelectedCountry(country);
      setIsDropdownOpen(false);
      
      // Revalider avec le nouveau pays
      if (localValue) {
        const result = validate(localValue, country);
        setValidationResult(result);
        
        const fullNumber = localValue ? `${country.dialCode} ${localValue}` : "";
        onValueChange?.(fullNumber, result.isValid, country);
        onChange?.(fullNumber);
      }
    },
    [localValue, validate, onValueChange, onChange]
  );

  // États dérivés
  const showError = touched && !validationResult.isValid && showValidation;
  const showSuccess = touched && validationResult.isValid && localValue.length > 0 && showValidation;
  const displayError = externalError || (showError ? validationResult.message : undefined);

  // Classes
  const inputClasses = cn(
    "w-full pl-32 pr-10 py-2.5 bg-white dark:bg-gray-900 border rounded-xl text-sm",
    "transition-all duration-200 focus:outline-none focus:ring-2",
    "placeholder:text-gray-400 dark:placeholder:text-gray-500",
    displayError
      ? "border-red-300 focus:border-red-500 focus:ring-red-200"
      : showSuccess
      ? "border-green-300 focus:border-green-500 focus:ring-green-200 dark:border-green-700"
      : "border-gray-200 dark:border-gray-700 focus:border-[#007E45] focus:ring-green-100/50",
    disabled && "opacity-50 cursor-not-allowed",
    className
  );

  return (
    <div className={cn("space-y-1.5", containerClassName)}>
      {/* Header */}
      <div className="flex justify-between items-center">
        <label className="text-xs font-medium text-gray-900 dark:text-gray-300">
          {label}
          {required && <span className="text-red-500 ml-0.5">*</span>}
        </label>

        {displayError && (
          <span className="text-[10px] text-red-500 font-medium flex items-center gap-1">
            <X className="w-3 h-3" />
            {displayError}
          </span>
        )}

        {showSuccess && !externalError && (
          <span className="text-[10px] text-green-500 font-medium flex items-center gap-1">
            <Check className="w-3 h-3" />
            Valide
          </span>
        )}
      </div>

      {/* Input avec sélecteur de pays */}
      <div className="relative">
        {/* Sélecteur de pays (bouton) */}
        <button
          type="button"
          onClick={() => !disabled && setIsDropdownOpen(!isDropdownOpen)}
          disabled={disabled}
          className={cn(
            "absolute left-0 top-0 h-full px-3 flex items-center gap-2 border-r",
            "bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors rounded-l-xl",
            disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
            displayError
              ? "border-red-300"
              : showSuccess
              ? "border-green-300"
              : "border-gray-200 dark:border-gray-700"
          )}
          style={{ width: "120px" }}
        >
          <span className="text-lg">{selectedCountry.flag}</span>
          <span className="text-xs font-medium text-gray-700 dark:text-gray-300">
            {selectedCountry.dialCode}
          </span>
          <ChevronDown
            className={cn(
              "w-3 h-3 text-gray-400 transition-transform ml-auto",
              isDropdownOpen && "rotate-180"
            )}
          />
        </button>

        {/* Input */}
        <input
          ref={ref}
          type="tel"
          name={name}
          id={id}
          value={localValue}
          onChange={handleChange}
          onBlur={handleBlur}
          disabled={disabled}
          placeholder={placeholder || selectedCountry.placeholder}
          aria-invalid={!!displayError}
          className={inputClasses}
        />

        {/* Icône téléphone à droite */}
        <div className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400">
          <Phone className="w-4 h-4" />
        </div>

        {/* Dropdown des pays */}
        {isDropdownOpen && (
          <>
            {/* Overlay pour fermer */}
            <div
              className="fixed inset-0 z-10"
              onClick={() => setIsDropdownOpen(false)}
            />

            {/* Liste des pays */}
            <div className="absolute z-20 top-full left-0 mt-1 w-full max-h-60 overflow-y-auto bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-xl">
              {COUNTRY_PHONES.map((country) => (
                <button
                  key={country.code}
                  type="button"
                  onClick={() => handleCountryChange(country)}
                  className={cn(
                    "w-full px-4 py-2.5 flex items-center gap-3 text-left hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors",
                    selectedCountry.code === country.code && "bg-green-50 dark:bg-green-900/20"
                  )}
                >
                  <span className="text-lg">{country.flag}</span>
                  <div className="flex-1 min-w-0">
                    <p className="text-xs font-medium text-gray-900 dark:text-white truncate">
                      {country.name}
                    </p>
                    <p className="text-[10px] text-gray-500">{country.format}</p>
                  </div>
                  <span className="text-xs font-medium text-gray-600 dark:text-gray-400">
                    {country.dialCode}
                  </span>
                  {selectedCountry.code === country.code && (
                    <Check className="w-4 h-4 text-green-500 flex-shrink-0" />
                  )}
                </button>
              ))}
            </div>
          </>
        )}
      </div>

      {/* Message d'aide */}
      {!displayError && !showSuccess && touched && (
        <p className="text-[10px] text-gray-500">
          Format attendu : {selectedCountry.format}
        </p>
      )}
    </div>
  );
});

InternationalPhoneInput.displayName = "InternationalPhoneInput";

// ============================================
// HOOK D'UTILISATION
// ============================================

export const useInternationalPhone = (defaultCountry: string = "FR") => {
  const [country, setCountry] = useState<CountryPhone>(
    COUNTRY_PHONES.find((c) => c.code === defaultCountry) || COUNTRY_PHONES[0]
  );
  const [phone, setPhone] = useState<string>("");
  const [isValid, setIsValid] = useState<boolean>(false);

  const handlePhoneChange = useCallback(
    (fullNumber: string, valid: boolean, selectedCountry: CountryPhone) => {
      setPhone(fullNumber);
      setIsValid(valid);
      setCountry(selectedCountry);
    },
    []
  );

  const getFullNumber = useCallback(() => {
    return `${country.dialCode} ${phone}`;
  }, [country, phone]);

  return {
    country,
    phone,
    isValid,
    fullNumber: getFullNumber(),
    handlePhoneChange,
  };
};