"""
Mapeo fila CSV → datos para Transporter.
Paridad Clarion LLENA_TRANSPORTISTAS / VALIDA_PARCIAL: en actualización, campo vacío en CSV usa valor existente.
UPPER aplicado según Clarion: NOMBRE CORTO, CODIGO POSTAL, PAIS, CODIGO CARGADOR, CODIGO CAAT, CODIGO TRANS, etc.
"""
from typing import Dict, Any, Optional, Union

from .common_validators import MAX_LEN


def _str_or_none(val: Any, max_len: Optional[int] = None, upper: bool = False) -> Optional[str]:
    if val is None:
        return None
    s = str(val).strip()
    if not s:
        return None
    if upper:
        s = s.upper()
    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:
    if existing is None:
        return None
    if isinstance(existing, dict):
        return existing.get(key)
    return getattr(existing, key, None)


def row_to_transporter_data(row_norm: Dict[str, Any]) -> Dict[str, Any]:
    """Build dict suitable for TransporterCreateDTO from normalized row (Clarion QueCSV → GenTra)."""
    transporter_key = _str_or_none(row_norm.get("CLAVE TRANSPORTISTA"), MAX_LEN["transporter_key"])
    if not transporter_key:
        return {}
    return {
        "transporter_key": transporter_key,
        "name": _str_or_none(row_norm.get("NOMBRE"), MAX_LEN["name"]),
        "short_name": _str_or_none(row_norm.get("NOMBRE CORTO"), MAX_LEN["short_name"], upper=True),
        "responsible": _str_or_none(row_norm.get("RESPONSABLE"), MAX_LEN["responsible"]),
        "rfc": _str_or_none(row_norm.get("RFC"), MAX_LEN["rfc"]),
        "streets": _str_or_none(row_norm.get("CALLES"), MAX_LEN["streets"]),
        "postal_code": _str_or_none(row_norm.get("CODIGO POSTAL"), MAX_LEN["postal_code"], upper=True),
        "city": _str_or_none(row_norm.get("CIUDAD"), MAX_LEN["city"]),
        "state": _str_or_none(row_norm.get("ESTADO"), MAX_LEN["state"]),
        "country": _str_or_none(row_norm.get("PAIS"), MAX_LEN["country"], upper=True),
        "loader_code": _str_or_none(row_norm.get("CODIGO CARGADOR"), MAX_LEN["loader_code"], upper=True),
        "caat_code": _str_or_none(row_norm.get("CODIGO CAAT"), MAX_LEN["caat_code"], upper=True),
        "transport_code": _str_or_none(row_norm.get("CODIGO TRANS"), MAX_LEN["transport_code"], upper=True),
        "transport_interface_type": _str_or_none(row_norm.get("TIPO INTERFASE TRANS"), MAX_LEN["transport_interface_type"]),
        "ftp_server": _str_or_none(row_norm.get("SERVIDOR FTP"), MAX_LEN["ftp_server"]),
        "ftp_user": _str_or_none(row_norm.get("USUARIO FTP"), MAX_LEN["ftp_user"]),
        "ftp_password": _str_or_none(row_norm.get("CLAVE ACCESO FTP"), MAX_LEN["ftp_password"]),
        "ftp_directory": _str_or_none(row_norm.get("DIRECTORIO FTP"), MAX_LEN["ftp_directory"]),
    }


def row_to_transporter_data_for_update(
    row_norm: Dict[str, Any],
    existing_transporter: Union[Any, Dict[str, Any]],
) -> Dict[str, Any]:
    """
    Build dict for TransporterUpdateDTO: CSV value if non-empty, else existing (Clarion VALIDA_PARCIAL).
    """
    transporter_key = _str_or_none(row_norm.get("CLAVE TRANSPORTISTA"), MAX_LEN["transporter_key"]) or _get_existing_val(existing_transporter, "transporter_key")
    if not transporter_key:
        return {}

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

    return {
        "transporter_key": transporter_key,
        "name": _csv_or_existing("NOMBRE", "name", MAX_LEN["name"]),
        "short_name": _csv_or_existing("NOMBRE CORTO", "short_name", MAX_LEN["short_name"], upper=True),
        "responsible": _csv_or_existing("RESPONSABLE", "responsible", MAX_LEN["responsible"]),
        "rfc": _csv_or_existing("RFC", "rfc", MAX_LEN["rfc"]),
        "streets": _csv_or_existing("CALLES", "streets", MAX_LEN["streets"]),
        "postal_code": _csv_or_existing("CODIGO POSTAL", "postal_code", MAX_LEN["postal_code"], upper=True),
        "city": _csv_or_existing("CIUDAD", "city", MAX_LEN["city"]),
        "state": _csv_or_existing("ESTADO", "state", MAX_LEN["state"]),
        "country": _csv_or_existing("PAIS", "country", MAX_LEN["country"], upper=True),
        "loader_code": _csv_or_existing("CODIGO CARGADOR", "loader_code", MAX_LEN["loader_code"], upper=True),
        "caat_code": _csv_or_existing("CODIGO CAAT", "caat_code", MAX_LEN["caat_code"], upper=True),
        "transport_code": _csv_or_existing("CODIGO TRANS", "transport_code", MAX_LEN["transport_code"], upper=True),
        "transport_interface_type": _csv_or_existing("TIPO INTERFASE TRANS", "transport_interface_type", MAX_LEN["transport_interface_type"]),
        "ftp_server": _csv_or_existing("SERVIDOR FTP", "ftp_server", MAX_LEN["ftp_server"]),
        "ftp_user": _csv_or_existing("USUARIO FTP", "ftp_user", MAX_LEN["ftp_user"]),
        "ftp_password": _csv_or_existing("CLAVE ACCESO FTP", "ftp_password", MAX_LEN["ftp_password"]),
        "ftp_directory": _csv_or_existing("DIRECTORIO FTP", "ftp_directory", MAX_LEN["ftp_directory"]),
    }
