"""
Validadores reutilizables para import CSV de trailers (longitudes, requerido).
Paridad Clarion: VALIDACIONES_TRAILER, código entidad C/I/A/B, catálogos tipo/país/estado, desfase.
"""
from typing import Dict, Any, Optional, Set, Tuple

# Max lengths from Trailer model (a76.trailer)
MAX_LEN = {
    "trailer_number": 20,
    "ace_trailer_number": 10,
    "trailer_type_key": 2,
    "seal": 15,
    "entity_code": 1,
    "plate_number": 17,
    "state": 30,
    "country": 3,
    "container_key": 3,
}

CODIGO_ENTIDAD_VALIDOS = {"C", "I", "A", "B"}


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 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 _get_codigo_entidad(row: Dict[str, Any]) -> str:
    return (row.get("CODIGO DE ENTIDAD") or row.get("CODIGO ENTIDAD") or "").strip()


def check_codigo_entidad_valores(row: Dict[str, Any], line_num: int) -> Optional[Dict[str, Any]]:
    """Col E: Si CODIGO DE ENTIDAD no vacío, debe ser C, I, A o B (Clarion)."""
    val = _get_codigo_entidad(row).upper()
    if not val:
        return None
    if val in CODIGO_ENTIDAD_VALIDOS:
        return None
    return {
        "line": line_num,
        "col": "CODIGO DE ENTIDAD",
        "msg": f"Error: (Col. E) El Codigo de Entidad: {val} es incorrecto.",
        "solution": "Capturar en columna E el Codigo de Entidad correcto, C, I, A ó B.",
    }


def check_trailer_type_catalog(
    row: Dict[str, Any],
    line_num: int,
    valid_trailer_type_keys: Optional[Set[str]] = None,
) -> Optional[Dict[str, Any]]:
    """Col C: Si TIPO TRAILER no vacío, debe existir en catálogo (GTipoTrailer)."""
    val = (row.get("TIPO TRAILER") or "").strip()
    if not val or valid_trailer_type_keys is None:
        return None
    if val.upper() in valid_trailer_type_keys:
        return None
    return {
        "line": line_num,
        "col": "TIPO TRAILER",
        "msg": f"Error: (Col. C) El Tipo de Trailer: {val} es incorrecto.",
        "solution": "Capturar en columna C un Tipo del Trailer existente.",
    }


def check_pais_catalog_trailers(
    row: Dict[str, Any],
    line_num: int,
    valid_country_ame: Optional[Set[str]] = None,
) -> Optional[Dict[str, Any]]:
    """Col H: Si PAIS 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 H{line_num}) El Pais: {val} Es Incorrecto",
            "solution": "Capturar en columna H 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. H) El Pais: {val} es incorrecto.",
        "solution": "Capturar en columna H el Pais del Transporte en Clave Americana.",
    }


def check_estado_catalog_trailers(
    row: Dict[str, Any],
    line_num: int,
    state_descriptions_upper: Optional[Set[str]] = None,
    state_ame_to_description: Optional[Dict[str, str]] = None,
) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
    """
    Col G: Si ESTADO no vacío, debe existir en catálogo (GEstados). Si hay estado, PAIS no puede estar vacío.
    Devuelve (error, estado_resuelto_upper). estado_resuelto_upper es la descripción en mayúsculas para estado-país.
    """
    state_ame_to_description = state_ame_to_description or {}
    val = (row.get("ESTADO") or "").strip()
    if not val or state_descriptions_upper is None:
        return None, None
    val_upper = val.upper()
    resolved_upper: Optional[str] = None
    if val_upper in state_descriptions_upper:
        resolved_upper = val_upper
    elif len(val) <= 2 and val_upper in state_ame_to_description:
        resolved_upper = state_ame_to_description[val_upper]
    if resolved_upper is None:
        return {
            "line": line_num,
            "col": "ESTADO",
            "msg": f"Error: (Celda G{line_num}) El Estado: {val} es incorrecto.",
            "solution": "Capturar en columna G el Estado del Trailer en Clave Americana o Nombre Completo.",
        }, None
    # Si existe estado, PAIS no puede estar vacío (Clarion)
    pais = (row.get("PAIS") or "").strip()
    if not pais:
        return {
            "line": line_num,
            "col": "PAIS",
            "msg": f"Error: (Celda G{line_num}) El Estado: {val} No esta ligado a ningun Pais.",
            "solution": "Capturar en columna H un Pais en Clave Americana(US = Estados Unidos, MX = Mexico, ES = España, etc).",
        }, None
    return None, resolved_upper


def check_estado_pais_consistency_trailers(
    row: Dict[str, Any],
    line_num: int,
    state_country_set: Optional[Set[Tuple[str, str]]] = None,
    estado_resuelto_upper: Optional[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
    desc_upper = estado_resuelto_upper or estado.upper()
    key = (pais, desc_upper)
    if key in state_country_set:
        return None
    return {
        "line": line_num,
        "col": "ESTADO",
        "msg": f"Error: (Col. G) EL Estado: {estado} no pertenece al Pais: {pais}.",
        "solution": "Capturar en columna G un Estado que pertenesca al Pais de la columna H.",
    }


def check_desfase_trailers(row: Dict[str, Any], line_num: int) -> Optional[Dict[str, Any]]:
    """Si COL_EXTRA 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 este en la posicion correcta.",
        "warning": True,
    }
