"""
Validación de paridad con import CSV (mismas reglas y fk_loader) para CRUD Transportes.
"""
from __future__ import annotations

from typing import Any, Dict, List, Optional, Set, Tuple

from sqlalchemy.orm import Session

from api.v1.common.catalog_validation_errors import CatalogValidationError

LINE = 1


def _raise_if_errors(errors: List[Dict[str, Any]]) -> None:
    if errors:
        raise CatalogValidationError(errors)


# --- Trailers ---


def trailer_fields_to_csv_row(d: Dict[str, Any]) -> Dict[str, Any]:
    return {
        "NUMERO TRAILER": (d.get("trailer_number") or "").strip(),
        "CLAVE ACE": (d.get("ace_trailer_number") or "").strip() if d.get("ace_trailer_number") is not None else "",
        "TIPO TRAILER": (d.get("trailer_type_key") or "").strip() if d.get("trailer_type_key") is not None else "",
        "PRECINTO": (d.get("seal") or "").strip() if d.get("seal") is not None else "",
        "CODIGO DE ENTIDAD": (d.get("entity_code") or "").strip() if d.get("entity_code") is not None else "",
        "PLACAS": (d.get("plate_number") or "").strip() if d.get("plate_number") is not None else "",
        "ESTADO": (d.get("state") or "").strip() if d.get("state") is not None else "",
        "PAIS": (d.get("country") or "").strip() if d.get("country") is not None else "",
        "CLAVE CONTENEDOR": (d.get("container_key") or "").strip() if d.get("container_key") is not None else "",
    }


def trailer_model_to_row(tr) -> Dict[str, Any]:
    return trailer_fields_to_csv_row(
        {
            "trailer_number": tr.trailer_number,
            "ace_trailer_number": tr.ace_trailer_number,
            "trailer_type_key": tr.trailer_type_key,
            "seal": tr.seal,
            "entity_code": tr.entity_code,
            "plate_number": tr.plate_number,
            "state": tr.state,
            "country": tr.country,
            "container_key": tr.container_key,
        }
    )


def validate_trailer_row_for_api(
    tenant_id: int,
    company_id: int,
    row: Dict[str, Any],
    *,
    is_update: bool,
    existing_trailer_numbers: Set[str],
) -> None:
    from api.v1.modules.a76.layouts_csv.trailers.common.fk_loader import load_trailers_fk_sets
    from api.v1.modules.a76.layouts_csv.trailers.validators.create import validate_row_trailer

    (
        valid_trailer_type_keys,
        valid_country_ame,
        state_descriptions_upper,
        state_country_set,
        state_ame_to_description,
    ) = load_trailers_fk_sets(tenant_id, company_id)

    clave = (row.get("NUMERO TRAILER") or "").strip()
    existing_norm = {x.strip() for x in existing_trailer_numbers if x}
    actualizar = is_update and bool(clave and clave in existing_norm)

    errs = validate_row_trailer(
        row,
        LINE,
        actualizar=actualizar,
        existing_trailer_numbers=existing_norm,
        valid_trailer_type_keys=valid_trailer_type_keys,
        valid_country_ame=valid_country_ame,
        state_descriptions_upper=state_descriptions_upper,
        state_country_set=state_country_set,
        state_ame_to_description=state_ame_to_description,
    )
    _raise_if_errors(errs)


# --- Vehicles ---


def _fmt_insurance_date(val: Any) -> str:
    if val is None:
        return ""
    if isinstance(val, int):
        return str(val)
    return str(val).strip()


def _fmt_monto(val: Any) -> str:
    if val is None:
        return ""
    if isinstance(val, float):
        return str(val)
    return str(val).strip()


def vehicle_fields_to_csv_row(d: Dict[str, Any]) -> Dict[str, Any]:
    return {
        "CLAVE": (d.get("vehicle_key") or "").strip(),
        "CLAVE ACE": (d.get("ace_vehicle_key") or "").strip() if d.get("ace_vehicle_key") is not None else "",
        "CLAVE TRANSPORTE": (d.get("transporter_key") or "").strip() if d.get("transporter_key") is not None else "",
        "VIN": (d.get("series") or "").strip() if d.get("series") is not None else "",
        "TIPO TRANSPORTE": (d.get("transport_type") or "").strip() if d.get("transport_type") is not None else "",
        "CODIGO DE ENTIDAD": (d.get("entity_code") or "").strip() if d.get("entity_code") is not None else "",
        "TRANSPONDEDOR": (d.get("transponder_number") or "").strip() if d.get("transponder_number") is not None else "",
        "NUMERO DOT": (d.get("dot_number") or "").strip() if d.get("dot_number") is not None else "",
        "PLACAS": (d.get("plate_number") or "").strip() if d.get("plate_number") is not None else "",
        "CIUDAD": (d.get("city") or "").strip() if d.get("city") is not None else "",
        "ESTADO": (d.get("state") or "").strip() if d.get("state") is not None else "",
        "PAIS": (d.get("country") or "").strip() if d.get("country") is not None else "",
        "PRECINTO": (d.get("seal") or "").strip() if d.get("seal") is not None else "",
        "EMPRESA ASEGURADORA": (d.get("insurance_company_name") or "").strip()
        if d.get("insurance_company_name") is not None
        else "",
        "NUM. ASEGURADORA": (d.get("insurance_number") or "").strip() if d.get("insurance_number") is not None else "",
        "MONTO ASEGURADO": _fmt_monto(d.get("insurance_amount")),
        "FECHA DE ASEGURADORA": _fmt_insurance_date(d.get("insurance_date")),
    }


def vehicle_model_to_row(v) -> Dict[str, Any]:
    return vehicle_fields_to_csv_row(
        {
            "vehicle_key": v.vehicle_key,
            "ace_vehicle_key": v.ace_vehicle_key,
            "transporter_key": v.transporter_key,
            "series": v.series,
            "transport_type": v.transport_type,
            "entity_code": v.entity_code,
            "transponder_number": v.transponder_number,
            "dot_number": v.dot_number,
            "plate_number": v.plate_number,
            "city": v.city,
            "state": v.state,
            "country": v.country,
            "seal": v.seal,
            "insurance_company_name": v.insurance_company_name,
            "insurance_number": v.insurance_number,
            "insurance_amount": float(v.insurance_amount) if v.insurance_amount is not None else None,
            "insurance_date": v.insurance_date,
        }
    )


def validate_vehicle_transporter_key(
    db: Session,
    tenant_id: int,
    company_id: int,
    transporter_key: Optional[str],
) -> None:
    if transporter_key is None or not str(transporter_key).strip():
        return
    from api.v1.modules.a76.transportation.transporters.services import TransporterService

    t = TransporterService.get_by_id_ignore_case(
        db, str(transporter_key).strip(), tenant_id, company_id
    )
    if not t:
        _raise_if_errors(
            [
                {
                    "line": LINE,
                    "col": "CLAVE TRANSPORTE",
                    "msg": f"El transportista '{transporter_key}' no existe en el catálogo de esta empresa.",
                }
            ]
        )


def validate_vehicle_row_for_api(
    db: Session,
    tenant_id: int,
    company_id: int,
    row: Dict[str, Any],
    *,
    is_update: bool,
    existing_vehicle_keys: Set[str],
) -> None:
    from api.v1.modules.a76.layouts_csv.vehicles.common.fk_loader import load_vehicles_fk_sets
    from api.v1.modules.a76.layouts_csv.vehicles.validators.create import validate_row_vehicle

    tk = (row.get("CLAVE TRANSPORTE") or "").strip()
    if tk:
        validate_vehicle_transporter_key(db, tenant_id, company_id, tk)

    (
        valid_transport_codes,
        valid_country_ame,
        state_descriptions_upper,
        state_country_set,
    ) = load_vehicles_fk_sets(tenant_id, company_id)

    clave = (row.get("CLAVE") or "").strip()
    existing_norm = {x.strip() for x in existing_vehicle_keys if x}
    actualizar = is_update and bool(clave and clave in existing_norm)

    errs = validate_row_vehicle(
        row,
        LINE,
        actualizar=actualizar,
        existing_vehicle_keys=existing_norm,
        valid_transport_codes=valid_transport_codes,
        valid_country_ame=valid_country_ame,
        state_descriptions_upper=state_descriptions_upper,
        state_country_set=state_country_set,
    )
    _raise_if_errors(errs)


# --- Transporters ---


def transporter_fields_to_csv_row(d: Dict[str, Any]) -> Dict[str, Any]:
    def s(k: str) -> str:
        v = d.get(k)
        if v is None:
            return ""
        return str(v).strip()

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


def transporter_model_to_row(t) -> Dict[str, Any]:
    return transporter_fields_to_csv_row(
        {
            "transporter_key": t.transporter_key,
            "name": t.name,
            "short_name": t.short_name,
            "responsible": t.responsible,
            "rfc": t.rfc,
            "streets": t.streets,
            "postal_code": t.postal_code,
            "city": t.city,
            "state": t.state,
            "country": t.country,
            "loader_code": t.loader_code,
            "caat_code": t.caat_code,
            "transport_code": t.transport_code,
            "transport_interface_type": t.transport_interface_type,
            "ftp_server": t.ftp_server,
            "ftp_user": t.ftp_user,
            "ftp_password": t.ftp_password,
            "ftp_directory": t.ftp_directory,
        }
    )


def validate_transporter_row_for_api(
    tenant_id: int,
    company_id: int,
    row: Dict[str, Any],
    *,
    is_update: bool,
    existing_transporter_keys: Set[str],
) -> None:
    from api.v1.modules.a76.layouts_csv.transportistas.common.fk_loader import load_transportistas_fk_sets
    from api.v1.modules.a76.layouts_csv.transportistas.validators.create import validate_row_transporter

    (
        existing_keys_loaded,
        valid_country_ame,
        state_descriptions_upper,
        state_country_set,
    ) = load_transportistas_fk_sets(tenant_id, company_id)

    clave = (row.get("CLAVE TRANSPORTISTA") or "").strip().upper()
    # existing set from loader is uppercased keys for this company
    existing_norm = existing_keys_loaded | {x.strip().upper() for x in existing_transporter_keys if x}
    actualizar = is_update and bool(clave and clave in existing_norm)

    errs = validate_row_transporter(
        row,
        LINE,
        actualizar=actualizar,
        existing_transporter_keys=existing_norm,
        valid_country_ame=valid_country_ame,
        state_descriptions_upper=state_descriptions_upper,
        state_country_set=state_country_set,
    )
    _raise_if_errors(errs)


# --- Drivers ---


def driver_fields_to_csv_row(d: Dict[str, Any]) -> Dict[str, Any]:
    def s(k: str) -> str:
        v = d.get(k)
        if v is None:
            return ""
        return str(v).strip()

    line = d.get("line")
    line_s = str(line) if line is not None else ""

    return {
        "TRANSPORTISTA": s("transporter_key"),
        "LINEA": line_s,
        "CLAVE CONDUCTOR": s("driver_name"),
        "LICENCIA": s("license_number"),
        "PERMISO LINEA EXPRESS": s("express_line_id"),
        "IDENTIFICACION ACE": s("ace_id"),
        "FECHA NACIMIENTO": str(d.get("birth_date")) if d.get("birth_date") is not None else "",
        "SEXO": s("gender"),
        "PAIS NACIMIENTO": s("birth_country"),
        "TRANSPORTA MAT. PELIGROSO?": s("hazardous_material_auth"),
        "PERMISO MAT. PELIGROSO": s("hazardous_material_state"),
        "NOMBRE(S)": s("first_name"),
        "APELLIDO PATERNO": s("last_name"),
        "FORMA IDENTIFICACION 1": s("id_key1"),
        "NUM. IDENTIFICACION 1": s("id_number1"),
        "ESTADO": s("id_state1"),
        "PAIS": s("id_country1"),
        "FORMA IDENTIFICACION 2": s("id_key2"),
        "NUM. IDENTIFICACION 2": s("id_number2"),
        "ESTADO 2": s("id_state2"),
        "PAIS 2": s("id_country2"),
    }


def validate_driver_row_for_api(
    tenant_id: int,
    company_id: int,
    row: Dict[str, Any],
    *,
    is_update: bool,
    existing_driver_keys: Set[Tuple[str, int]],
) -> None:
    from api.v1.modules.a76.layouts_csv.drivers.common.fk_loader import load_drivers_fk_sets
    from api.v1.modules.a76.layouts_csv.drivers.validators.create import validate_row_driver

    valid_transporter_keys, valid_country_ame, _ = load_drivers_fk_sets(tenant_id, company_id)

    transporter_key = (row.get("TRANSPORTISTA") or "").strip().upper()
    from api.v1.modules.a76.layouts_csv.drivers.common.common_validators import parse_int

    line = parse_int(row.get("LINEA"))
    actualizar = is_update and bool(transporter_key and line is not None) and (transporter_key, line) in existing_driver_keys

    errs = validate_row_driver(
        row,
        LINE,
        actualizar=actualizar,
        existing_driver_keys=existing_driver_keys,
        valid_transporter_keys=valid_transporter_keys,
        valid_country_ame=valid_country_ame,
    )
    _raise_if_errors(errs)
