import { cn } from "@/lib/utils";
import { useState, useCallback, forwardRef, InputHTMLAttributes } from "react";

// ============================================
// TYPES
// ============================================

type InputType = 
  | "text" 
  | "email" 
  | "phone" 
  | "siret" 
  | "siren" 
  | "iban" 
  | "bic" 
  | "password"
  | "number"
  | "url"
  | "postal_code"
  | "tva_intra";

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

interface InputFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {
  label: string;
  inputType?: InputType;
  required?: boolean;
  error?: string;
  className?: string;
  containerClassName?: string;
  showValidation?: boolean;
  onValueChange?: (value: string, isValid: boolean) => void;
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
}

// ============================================
// VALIDATEURS
// ============================================

const validators: Record<InputType, (value: string) => ValidationResult> = {
  text: (value) => ({ isValid: value.length > 0, message: "Ce champ est requis" }),
  
  email: (value) => {
    const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
    return {
      isValid: regex.test(value),
      message: "Format email invalide (ex: exemple@domaine.fr)"
    };
  },
  
  phone: (value) => {
    // Format français: 06 12 34 56 78 ou +33 6 12 34 56 78
    const cleaned = value.replace(/[\s.-]/g, "");
    const regexFR = /^(?:(?:\+|00)33|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/;
    const regexSimple = /^(0[1-9])(\d{8})$|^(\+33|0033)[1-9](\d{8})$/;
    return {
      isValid: regexFR.test(value) || regexSimple.test(cleaned),
      message: "Format: 06 12 34 56 78 ou +33 6 12 34 56 78"
    };
  },
  
  siret: (value) => {
    const cleaned = value.replace(/\s/g, "");
    if (!/^\d{14}$/.test(cleaned)) {
      return { isValid: false, message: "Le SIRET doit contenir 14 chiffres" };
    }
    // Validation Luhn
    let sum = 0;
    for (let i = 0; i < 14; i++) {
      let digit = parseInt(cleaned[i], 10);
      if (i % 2 === 0) {
        digit *= 2;
        if (digit > 9) digit -= 9;
      }
      sum += digit;
    }
    return {
      isValid: sum % 10 === 0,
      message: "SIRET invalide (vérification Luhn échouée)"
    };
  },
  
  siren: (value) => {
    const cleaned = value.replace(/\s/g, "");
    if (!/^\d{9}$/.test(cleaned)) {
      return { isValid: false, message: "Le SIREN doit contenir 9 chiffres" };
    }
    // Validation Luhn
    let sum = 0;
    for (let i = 0; i < 9; i++) {
      let digit = parseInt(cleaned[i], 10);
      if (i % 2 === 1) {
        digit *= 2;
        if (digit > 9) digit -= 9;
      }
      sum += digit;
    }
    return {
      isValid: sum % 10 === 0,
      message: "SIREN invalide (vérification Luhn échouée)"
    };
  },
  
  iban: (value) => {
    const cleaned = value.replace(/\s/g, "").toUpperCase();
    // IBAN français: FR + 2 chiffres + 23 caractères alphanumériques
    if (!/^[A-Z]{2}\d{2}[A-Z0-9]{4,30}$/.test(cleaned)) {
      return { isValid: false, message: "Format IBAN invalide" };
    }
    // Validation mod 97
    const rearranged = cleaned.slice(4) + cleaned.slice(0, 4);
    const numericIBAN = rearranged.replace(/[A-Z]/g, (char) => 
      (char.charCodeAt(0) - 55).toString()
    );
    let remainder = numericIBAN;
    while (remainder.length > 2) {
      const block = remainder.slice(0, 9);
      remainder = (parseInt(block, 10) % 97).toString() + remainder.slice(9);
    }
    return {
      isValid: parseInt(remainder, 10) % 97 === 1,
      message: "IBAN invalide (vérification mod-97 échouée)"
    };
  },
  
  bic: (value) => {
    const cleaned = value.replace(/\s/g, "").toUpperCase();
    // BIC: 8 ou 11 caractères (AAAABBCC ou AAAABBCCDDD)
    const regex = /^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$/;
    return {
      isValid: regex.test(cleaned),
      message: "Format BIC: 8 ou 11 caractères (ex: BNPAFRPP)"
    };
  },
  
  password: (value) => {
    const hasMinLength = value.length >= 8;
    const hasUppercase = /[A-Z]/.test(value);
    const hasLowercase = /[a-z]/.test(value);
    const hasNumber = /\d/.test(value);
    const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(value);
    
    const isValid = hasMinLength && hasUppercase && hasLowercase && hasNumber;
    let message = "Requis: ";
    const missing = [];
    if (!hasMinLength) missing.push("8+ caractères");
    if (!hasUppercase) missing.push("majuscule");
    if (!hasLowercase) missing.push("minuscule");
    if (!hasNumber) missing.push("chiffre");
    
    return {
      isValid,
      message: missing.length > 0 ? message + missing.join(", ") : undefined
    };
  },
  
  number: (value) => {
    const isValid = !isNaN(Number(value)) && value.trim() !== "";
    return { isValid, message: "Veuillez entrer un nombre valide" };
  },
  
  url: (value) => {
    try {
      new URL(value);
      return { isValid: true };
    } catch {
      return { isValid: false, message: "URL invalide (ex: https://exemple.fr)" };
    }
  },
  
  postal_code: (value) => {
    const regex = /^(?:0[1-9]|[1-8]\d|9[0-8])\d{3}$/;
    return {
      isValid: regex.test(value),
      message: "Code postal français invalide (5 chiffres)"
    };
  },
  
  tva_intra: (value) => {
    const cleaned = value.replace(/\s/g, "").toUpperCase();
    // TVA intracommunautaire française: FR + 2 caractères + SIREN (9 chiffres)
    const regex = /^FR[0-9A-Z]{2}\d{9}$/;
    if (!regex.test(cleaned)) {
      return { isValid: false, message: "Format: FRXX123456789" };
    }
    return { isValid: true };
  }
};

// ============================================
// FORMATEURS (pour affichage)
// ============================================

const formatters: Partial<Record<InputType, (value: string) => string>> = {
  phone: (value) => {
    const cleaned = value.replace(/\D/g, "");
    if (cleaned.startsWith("33")) {
      return cleaned.replace(/(\d{2})(\d{1})(\d{2})(\d{2})(\d{2})(\d{2})/, "+$1 $2 $3 $4 $5 $6");
    }
    return cleaned.replace(/(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/, "$1 $2 $3 $4 $5");
  },
  
  siret: (value) => {
    const cleaned = value.replace(/\D/g, "").slice(0, 14);
    return cleaned.replace(/(\d{3})(\d{3})(\d{3})(\d{5})/, "$1 $2 $3 $4");
  },
  
  siren: (value) => {
    const cleaned = value.replace(/\D/g, "").slice(0, 9);
    return cleaned.replace(/(\d{3})(\d{3})(\d{3})/, "$1 $2 $3");
  },
  
  iban: (value) => {
    const cleaned = value.replace(/\s/g, "").toUpperCase().slice(0, 34);
    return cleaned.replace(/(.{4})/g, "$1 ").trim();
  },
  
  bic: (value) => value.toUpperCase().replace(/\s/g, "").slice(0, 11)
};

// ============================================
// PLACEHOLDERS
// ============================================

const placeholders: Partial<Record<InputType, string>> = {
  email: "exemple@domaine.fr",
  phone: "06 12 34 56 78",
  siret: "123 456 789 00012",
  siren: "123 456 789",
  iban: "FR76 1234 5678 9012 3456 7890 123",
  bic: "BNPAFRPP",
  postal_code: "75001",
  tva_intra: "FR12345678901",
  url: "https://exemple.fr"
};

// ============================================
// STYLES
// ============================================

export const inputClass = (error?: boolean, isValid?: boolean) => cn(
  "w-full px-3 py-2.5 bg-white dark:bg-gray-900 border rounded-xl text-sm transition-all focus:outline-none focus:ring-2",
  error
    ? "border-green-300 focus:border-green-500 focus:ring-green-200"
    : isValid
      ? "border-green-300 focus:border-green-500 focus:ring-green-200"
      : "border-gray-200 dark:border-gray-700 focus:border-[#007E45] focus:ring-red-100/50"
);

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

export const InputField = forwardRef<HTMLInputElement, InputFieldProps>(({
  label,
  inputType = "text",
  required = false,
  error: externalError,
  className = "",
  containerClassName = "",
  showValidation = true,
  onValueChange,
  onChange,
  value: controlledValue,
  ...props
}, ref) => {
  const [internalValue, setInternalValue] = useState("");
  const [touched, setTouched] = useState(false);
  const [validationResult, setValidationResult] = useState<ValidationResult>({ isValid: true });
  
  const value = controlledValue !== undefined ? String(controlledValue) : internalValue;
  
  const validate = useCallback((val: string) => {
    if (!val && !required) {
      return { isValid: true };
    }
    if (!val && required) {
      return { isValid: false, message: "Ce champ est requis" };
    }
    return validators[inputType](val);
  }, [inputType, required]);
  
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    let newValue = e.target.value;
    
    // Appliquer le formateur si disponible
    const formatter = formatters[inputType];
    if (formatter) {
      newValue = formatter(newValue);
    }
    
    if (controlledValue === undefined) {
      setInternalValue(newValue);
    }
    
    const result = validate(newValue);
    setValidationResult(result);
    
    onValueChange?.(newValue, result.isValid);
    
    // Créer un nouvel événement avec la valeur formatée
    const syntheticEvent = {
      ...e,
      target: { ...e.target, value: newValue }
    } as React.ChangeEvent<HTMLInputElement>;
    onChange?.(syntheticEvent);
  };
  
  const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
    setTouched(true);
    const result = validate(value);
    setValidationResult(result);
    props.onBlur?.(e);
  };
  
  const showError = touched && !validationResult.isValid && showValidation;
  const showSuccess = touched && validationResult.isValid && value && showValidation;
  const displayError = externalError || (showError ? validationResult.message : undefined);
  
  // Déterminer le type HTML natif
  const htmlType = inputType === "email" ? "email" 
    : inputType === "password" ? "password"
    : inputType === "number" ? "number"
    : inputType === "url" ? "url"
    : "text";
  
  return (
    <div className={cn("space-y-1.5", containerClassName)}>
      <div className="flex justify-between items-center">
        <label className="text-xs font-medium text-gray-700 dark:text-gray-300">
          {label} {required && <span className="text-[#941403]">*</span>}
        </label>
        {displayError && (
          <span className="text-[10px] text-red-500 font-medium flex items-center gap-1">
            <svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
              <path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
            </svg>
            {displayError}
          </span>
        )}
        {showSuccess && !externalError && (
          <span className="text-[10px] text-green-500 font-medium flex items-center gap-1">
            <svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
              <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
            </svg>
            Valide
          </span>
        )}
      </div>
      <div className="relative">
        <input
          ref={ref}
          type={htmlType}
          value={value}
          onChange={handleChange}
          onBlur={handleBlur}
          placeholder={placeholders[inputType] || props.placeholder}
          className={cn(
            inputClass(!!displayError, !!showSuccess),
            className
          )}
          {...props}
        />
        {/* Icône indicateur */}
        {touched && showValidation && (
          <div className="absolute right-3 top-1/2 -translate-y-1/2">
            {showSuccess && !externalError ? (
              <svg className="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20">
                <path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
              </svg>
            ) : showError ? (
              <svg className="w-4 h-4 text-red-500" fill="currentColor" viewBox="0 0 20 20">
                <path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
              </svg>
            ) : null}
          </div>
        )}
      </div>
    </div>
  );
});

InputField.displayName = "InputField";

// ============================================
// HOOK DE VALIDATION (pour usage externe)
// ============================================

export const useValidation = (inputType: InputType) => {
  return useCallback((value: string) => validators[inputType](value), [inputType]);
};
