"""
Validadores reutilizables para import CSV de transportistas.
Paridad Clarion: VALIDACIONES_TRANSPORTISTAS (estado, país, estado-país), desfase Col S.
"""
from typing import Dict, Any, Optional, Set, Tuple

# Max lengths from Transporter model (a76.transporter)
MAX_LEN = {
    "transporter_key": 23,
    "name": 256,
    "short_name": 10,
    "responsible": 100,
    "rfc": 30,
    "streets": 100,
    "postal_code": 15,
    "city": 30,
    "state": 30,
    "country": 3,
    "loader_code": 9,
    "caat_code": 49,
    "transport_code": 8,
    "transport_interface_type": 20,
    "ftp_server": 200,
    "ftp_user": 200,
    "ftp_password": 100,
    "ftp_directory": 1000,
}


def check_required(row: Dict[str, Any], col: str, max_len: int, line_num: int) -> Optional[Dict[str, Any]]:
    val = (row.get(col) or "").strip()
    if not val:
        return {"line": line_num, "col": col, "msg": "Requerido"}
    if max_len and len(val) > max_len:
        return {"line": line_num, "col": col, "msg": f"Máximo {max_len} caracteres"}
    return None


def check_max_length(
    row: Dict[str, Any],
    col: str,
    max_len: int,
    line_num: int,
    required: bool = False,
) -> Optional[Dict[str, Any]]:
    val = (row.get(col) or "").strip()
    if not val:
        if required:
            return {"line": line_num, "col": col, "msg": "Requerido"}
        return None
    if len(val) > max_len:
        return {"line": line_num, "col": col, "msg": f"Máximo {max_len} caracteres"}
    return None


def check_desfase_transportistas(row: Dict[str, Any], line_num: int) -> Optional[Dict[str, Any]]:
    """Si COL_EXTRA (columna 19 / Col S) tiene valor → advertencia de desfase (Clarion, no bloqueante)."""
    val = (row.get("COL_EXTRA") or "").strip()
    if not val:
        return None
    return {
        "line": line_num,
        "col": "COL_EXTRA",
        "msg": "Advertencia: Podría existir un desfase en esta línea.",
        "solution": "Revisar esta línea del archivo CSV y verificar cada campo esté en la posición correcta.",
        "warning": True,
    }


def check_pais_catalog_transportistas(
    row: Dict[str, Any],
    line_num: int,
    valid_country_ame: Optional[Set[str]] = None,
) -> Optional[Dict[str, Any]]:
    """Col J (PAIS): Si no vacío, debe ser clave americana (2 chars) y existir en catálogo (GPaises.Pais_Ame)."""
    val = (row.get("PAIS") or "").strip()
    if not val or valid_country_ame is None:
        return None
    val_upper = val.upper()
    if len(val) > 2:
        return {
            "line": line_num,
            "col": "PAIS",
            "msg": f"Error: (Celda J{line_num}) El Pais: {val} Es Incorrecto",
            "solution": "Capturar en columna J un Pais en Clave Americana(US = Estados Unidos, MX = Mexico, ES = España, etc).",
        }
    if val_upper in valid_country_ame:
        return None
    return {
        "line": line_num,
        "col": "PAIS",
        "msg": f"Error: (Col. J) El Pais: {val} es incorrecto.",
        "solution": "Capturar en columna J el Pais del Transportista en Clave Americana.",
    }


def check_estado_catalog_transportistas(
    row: Dict[str, Any],
    line_num: int,
    state_descriptions_upper: Optional[Set[str]] = None,
) -> Optional[Dict[str, Any]]:
    """Col I (ESTADO): Si no vacío, debe existir en catálogo (GEstados por descripción). Si hay estado, PAIS no puede estar vacío."""
    val = (row.get("ESTADO") or "").strip()
    if not val or state_descriptions_upper is None:
        return None
    val_upper = val.upper()
    if val_upper not in state_descriptions_upper:
        return {
            "line": line_num,
            "col": "ESTADO",
            "msg": f"Error: (Celda I{line_num}) El Estado: {val} es incorrecto.",
            "solution": "Capturar en columna I el Estado del Transportista en Clave Americana o Nombre Completo.",
        }
    pais = (row.get("PAIS") or "").strip()
    if not pais:
        return {
            "line": line_num,
            "col": "PAIS",
            "msg": f"Error: (Celda I{line_num}) El Estado: {val} No esta ligado a ningun Pais.",
            "solution": "Capturar en columna J un Pais en Clave Americana(US = Estados Unidos, MX = Mexico, ES = España, etc).",
        }
    return None


def check_estado_pais_consistency_transportistas(
    row: Dict[str, Any],
    line_num: int,
    state_country_set: Optional[Set[Tuple[str, str]]] = None,
) -> Optional[Dict[str, Any]]:
    """Si hay ESTADO y PAIS, validar que el estado pertenezca al país (Clarion GEstados-GPaises)."""
    estado = (row.get("ESTADO") or "").strip()
    pais = (row.get("PAIS") or "").strip().upper()
    if not estado or not pais or state_country_set is None:
        return None
    key = (pais, estado.upper())
    if key in state_country_set:
        return None
    return {
        "line": line_num,
        "col": "ESTADO",
        "msg": f"Error: (Col. I) EL Estado: {estado} no pertenece al Pais: {pais}.",
        "solution": "Capturar en columna I un Estado que pertenesca al Pais de la columna J.",
    }
