"""Mapeo y validación de transporte para CSV (paridad con facturas manuales / validate_common)."""

from __future__ import annotations

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

from sqlalchemy import func
from sqlalchemy.orm import Session

from api.v1.modules.a76.invoices.models import TransportType


def normalize_transport_cell(raw: Optional[str]) -> str:
    if raw is None:
        return ""
    return str(raw).replace("\u00a0", " ").strip()


def resolve_transport_csv_fields(row: dict) -> Tuple[str, str, str]:
    """
    Prioridad de columnas:
    1) CLAVE TRANSPORTE / NUMERO CAJA
    2) NUMERO TRANSPORTE como fallback legacy.
    """
    legacy = normalize_transport_cell(row.get("NUMERO TRANSPORTE"))
    clave_transporte = normalize_transport_cell(row.get("CLAVE TRANSPORTE")) or legacy
    numero_caja = normalize_transport_cell(row.get("NUMERO CAJA")) or legacy
    numero_transporte = legacy
    return clave_transporte, numero_caja, numero_transporte


def resolve_logistics_transport_fields_for_commit(
    session: Session,
    tenant_id: int,
    company_id: int,
    clave_transporte_raw: str,
    numero_caja_raw: str,
) -> Tuple[Optional[str], Optional[str], Optional[int], Optional[int]]:
    """
    Resuelve claves y IDs internos para logística:
    - transport_id / transport_int_id a partir de Vehicle.vehicle_key
    - trailer_num / trailer_int_id a partir de Trailer.trailer_number
    """
    from api.v1.modules.a76.transportation.vehicles.models import Vehicle
    from api.v1.modules.a76.transportation.trailers.models import Trailer

    clave_transporte = normalize_transport_cell(clave_transporte_raw)
    numero_caja = normalize_transport_cell(numero_caja_raw)

    transport_id: Optional[str] = clave_transporte or None
    trailer_num: Optional[str] = numero_caja or None
    transport_int_id: Optional[int] = None
    trailer_int_id: Optional[int] = None

    if transport_id:
        vehicle = (
            session.query(Vehicle)
            .filter(
                func.upper(Vehicle.vehicle_key) == transport_id.upper(),
                Vehicle.tenant_id == tenant_id,
                Vehicle.company_id == company_id,
            )
            .first()
        )
        if vehicle is not None:
            transport_int_id = vehicle.vehicle_id

    if trailer_num:
        trailer = (
            session.query(Trailer)
            .filter(
                func.upper(Trailer.trailer_number) == trailer_num.upper(),
                Trailer.tenant_id == tenant_id,
                Trailer.company_id == company_id,
            )
            .first()
        )
        if trailer is not None:
            trailer_int_id = trailer.trailer_id

    return transport_id, trailer_num, transport_int_id, trailer_int_id


def validate_csv_invoice_logistics_transport(
    row_norm: dict,
    session: Session,
    tenant_id: int,
    company_id: int,
    transport_type: TransportType,
) -> Optional[str]:
    """
    Paridad con validate_common (factura manual):
    - Transportista y conductor: solo catálogo si vienen informados.
    - Vehículo: solo catálogo si viene CLAVE TRANSPORTE explícita y no resuelve.
    - Remolque: obligatorio (y catálogo) si tipo ≠ none; con none, solo catálogo si NUMERO CAJA explícito.
    """
    from api.v1.modules.a76.transportation.transporters.models import Transporter
    from api.v1.modules.a76.transportation.drivers.models import Driver

    carrier_code = normalize_transport_cell(row_norm.get("CLAVE TRANSPORTISTA"))
    carrier_ok = False
    if carrier_code:
        tr_obj = (
            session.query(Transporter)
            .filter(
                Transporter.transporter_key == carrier_code,
                Transporter.tenant_id == tenant_id,
                Transporter.company_id == company_id,
            )
            .first()
        )
        if not tr_obj:
            return "CLAVE TRANSPORTISTA no existe en el catálogo"
        carrier_ok = True

    driver_raw = normalize_transport_cell(row_norm.get("NOMBRE CONDUCTOR"))
    if carrier_ok and driver_raw:
        dr = (
            session.query(Driver)
            .filter(
                Driver.transporter_key == carrier_code,
                Driver.driver_name == driver_raw,
                Driver.tenant_id == tenant_id,
                Driver.company_id == company_id,
            )
            .first()
        )
        if not dr:
            return (
                "NOMBRE CONDUCTOR: no existe en el catálogo de conductores "
                "para el transportista indicado"
            )

    transport_key_csv, trailer_num_csv, _ = resolve_transport_csv_fields(row_norm)
    (
        _transport_id_value,
        trailer_num_resolved,
        transport_int_id,
        trailer_int_id,
    ) = resolve_logistics_transport_fields_for_commit(
        session=session,
        tenant_id=tenant_id,
        company_id=company_id,
        clave_transporte_raw=transport_key_csv,
        numero_caja_raw=trailer_num_csv,
    )

    explicit_clave = normalize_transport_cell(row_norm.get("CLAVE TRANSPORTE"))
    if explicit_clave and transport_int_id is None:
        return "CLAVE TRANSPORTE: vehículo no existe en el catálogo"

    explicit_caja = normalize_transport_cell(row_norm.get("NUMERO CAJA"))
    if transport_type == TransportType.NONE:
        if explicit_caja and trailer_int_id is None:
            return "NUMERO CAJA: remolque no existe en el catálogo"
        return None

    if trailer_int_id is None:
        if not (trailer_num_resolved and str(trailer_num_resolved).strip()):
            return (
                "NUMERO CAJA (remolque) obligatorio cuando TIPO TRANSPORTE es distinto de NINGUNO"
            )
        return "NUMERO CAJA: remolque no existe en el catálogo"

    return None


def _csv_row_has_resolved_weight_unit(row_norm: dict) -> bool:
    """
    Paridad con insert_valid_rows: has_logistics_data incluye parse_weight_unit(TIPO PESO).
    Import diferido para evitar ciclo al cargar tasks.
    """
    from api.v1.modules.a76.layouts_csv.facturas.tasks import parse_weight_unit

    return parse_weight_unit(row_norm.get("TIPO PESO")) is not None


def logistics_scan_row_errors(
    row_norm: dict,
    session: Session,
    tenant_id: int,
    company_id: int,
    line_num: int,
) -> List[Dict[str, Any]]:
    """
    Errores de scan (misma lógica que commit: validate_csv_invoice_logistics_transport).
    Solo corre si la fila trae algún dato de logística de transporte.
    """
    from .encabezados_impo_temp import row_to_transport_type_clarion

    transport_key_csv, trailer_num_csv, _ = resolve_transport_csv_fields(row_norm)

    def _cell(key: str) -> str:
        return normalize_transport_cell(row_norm.get(key))

    has_data = bool(
        _cell("TIPO TRANSPORTE")
        or _cell("NUMERO TRANSPORTE")
        or _cell("CLAVE TRANSPORTE")
        or transport_key_csv
        or trailer_num_csv
        or _cell("CLAVE TRANSPORTISTA")
        or _cell("NOMBRE CONDUCTOR")
        or _csv_row_has_resolved_weight_unit(row_norm)
    )
    if not has_data:
        return []

    raw_transport = row_norm.get("TIPO TRANSPORTE")
    transport_str = (
        row_to_transport_type_clarion(raw_transport)
        or str(raw_transport or "").strip().lower()
        or "none"
    )
    try:
        tt = TransportType(transport_str)
    except ValueError:
        tt = TransportType.NONE

    msg = validate_csv_invoice_logistics_transport(
        row_norm=row_norm,
        session=session,
        tenant_id=tenant_id,
        company_id=company_id,
        transport_type=tt,
    )
    if not msg:
        return []
    return [
        {
            "line": line_num,
            "col": "LOGISTICA TRANSPORTE",
            "msg": msg,
            "solution": (
                "Verifica CLAVE TRANSPORTISTA, NOMBRE CONDUCTOR, CLAVE TRANSPORTE, "
                "NUMERO CAJA y TIPO TRANSPORTE (remolque obligatorio si no es NINGUNO)."
            ),
        }
    ]
