"""
Mapeo fila CSV → datos para Trailer.
Paridad Clarion LLENA_TRAILER: en actualización, campo vacío en CSV usa valor existente del trailer.
"""
from typing import Dict, Any, Optional, Union

from .common_validators import MAX_LEN


def _str_or_none(val: Any, max_len: Optional[int] = None) -> Optional[str]:
    if val is None:
        return None
    s = str(val).strip()
    if not s:
        return None
    if max_len and len(s) > max_len:
        return s[:max_len]
    return s


def _get_existing_val(existing: Union[Any, Dict[str, Any]], key: str) -> Any:
    """Obtiene valor del trailer existente (modelo ORM o dict)."""
    if existing is None:
        return None
    if isinstance(existing, dict):
        return existing.get(key)
    return getattr(existing, key, None)


def _get_entity_code(row_norm: Dict[str, Any]) -> Optional[str]:
    return _str_or_none(
        row_norm.get("CODIGO ENTIDAD") or row_norm.get("CODIGO DE ENTIDAD"),
        MAX_LEN["entity_code"],
    )


def row_to_trailer_data(row_norm: Dict[str, Any]) -> Dict[str, Any]:
    """Build dict for TrailerCreateDTO / TrailerUpdateDTO from normalized row."""
    trailer_number = _str_or_none(
        row_norm.get("NUMERO TRAILER") or row_norm.get("CLAVE TRAILER"),
        MAX_LEN["trailer_number"],
    )
    if not trailer_number:
        return {}
    return {
        "trailer_number": trailer_number,
        "ace_trailer_number": _str_or_none(row_norm.get("CLAVE ACE"), MAX_LEN["ace_trailer_number"]),
        "trailer_type_key": _str_or_none(row_norm.get("TIPO TRAILER"), MAX_LEN["trailer_type_key"]),
        "seal": _str_or_none(row_norm.get("PRECINTO"), MAX_LEN["seal"]),
        "entity_code": _get_entity_code(row_norm),
        "plate_number": _str_or_none(row_norm.get("PLACAS"), MAX_LEN["plate_number"]),
        "state": _str_or_none(row_norm.get("ESTADO"), MAX_LEN["state"]),
        "country": _str_or_none(row_norm.get("PAIS"), MAX_LEN["country"]),
        "container_key": _str_or_none(row_norm.get("CLAVE CONTENEDOR"), MAX_LEN["container_key"]),
    }


def row_to_trailer_data_for_update(
    row_norm: Dict[str, Any],
    existing_trailer: Union[Any, Dict[str, Any]],
) -> Dict[str, Any]:
    """
    Build dict for TrailerUpdateDTO: CSV value if non-empty, else existing trailer value (Clarion VALIDA_PARCIAL / LLENA_TRAILER).
    """
    trailer_number = _str_or_none(
        row_norm.get("NUMERO TRAILER") or row_norm.get("CLAVE TRAILER"),
        MAX_LEN["trailer_number"],
    ) or _get_existing_val(existing_trailer, "trailer_number")
    if not trailer_number:
        return {}

    def _csv_or_existing(csv_key: str, dto_key: str, max_len: Optional[int] = None):
        v = _str_or_none(row_norm.get(csv_key), max_len)
        if v is not None and v != "":
            return v
        return _get_existing_val(existing_trailer, dto_key)

    def _entity_code_or_existing():
        v = _get_entity_code(row_norm)
        if v is not None and v != "":
            return v
        return _get_existing_val(existing_trailer, "entity_code")

    return {
        "trailer_number": trailer_number,
        "ace_trailer_number": _csv_or_existing("CLAVE ACE", "ace_trailer_number", MAX_LEN["ace_trailer_number"]),
        "trailer_type_key": _csv_or_existing("TIPO TRAILER", "trailer_type_key", MAX_LEN["trailer_type_key"]),
        "seal": _csv_or_existing("PRECINTO", "seal", MAX_LEN["seal"]),
        "entity_code": _entity_code_or_existing(),
        "plate_number": _csv_or_existing("PLACAS", "plate_number", MAX_LEN["plate_number"]),
        "state": _csv_or_existing("ESTADO", "state", MAX_LEN["state"]),
        "country": _csv_or_existing("PAIS", "country", MAX_LEN["country"]),
        "container_key": _csv_or_existing("CLAVE CONTENEDOR", "container_key", MAX_LEN["container_key"]),
    }
