from decimal import Decimal

from sqlalchemy.orm import Session

from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasureCustoms
from api.v1.modules.a76.items.models import LineItem
from core.exceptions import ErrorCollector

from .review_equivalence import _get_unit_equivalence

def revisa_uma(
    db: Session,
    line: LineItem,
    tenant_id: str,
    company_id: str,
    errors: ErrorCollector,
) -> None:
    """
    Revisa la unidad de medida americana (UMA) de aduana para una partida.
    Paridad: REVISA_UMA (Clarion SCAII).

    Flujo:
    1. Verifica que la UM de la partida exista en el catálogo GUnimedida.
    2. Verifica que esa UM tenga asignada una Clave_AMex (UM aduana mexicana).
    3. Verifica que la Clave_AMex exista en el catálogo GUMAduana.
    4. Verifica que el registro de aduana tenga una UnidadSCAII (a76_unit_code).
    5. Calcula la cantidad UMA:
       - Si la UM de la partida coincide con UnidadSCAII → cantidad directa.
       - Si no → busca conversión en el catálogo de equivalencias.
    6. Escribe CantImpoUMA y ClaveUMA de regreso en la partida.
    """
    uom = line.unit_of_measure_info
    line_um_code = uom.code if uom else ""

    # ── 1. Verificar existencia de la UM en el catálogo ──────────────────────
    if uom is None:
        errors.add_error(
            field=f"line[{line.line_number}].unit_of_measure",
            message=(
                f"No existe la unidad de medida {line_um_code}"
                " en el catálogo de Unidades de Medida."
            ),
            solution=["Capturarla en el catálogo de Unidades de Medida."],
            code="UNIMEDIDA",
        )
        return

    # ── 2. Verificar que tenga Clave_AMex asignada ───────────────────────────
    customs_code = uom.customs_code or ""
    if not customs_code:
        errors.add_error(
            field=f"line[{line.line_number}].unit_of_measure",
            message=(
                f"No existe la unidad de medida de la aduana para la unidad de medida "
                f"{line_um_code} en el catálogo de Unidades de Medida."
            ),
            solution=["Asignar la U.M.A en el catálogo de Unidades de Medida."],
            code="UNIMEDIDA",
        )
        return

    # ── 3. Buscar la UM en el catálogo de Aduana Mex (GUMAduana) ─────────────
    customs_uom = (
        db.query(UnitOfMeasureCustoms)
        .filter(UnitOfMeasureCustoms.code == customs_code)
        .first()
    )

    if customs_uom is None:
        errors.add_error(
            field=f"line[{line.line_number}].unit_of_measure",
            message=(
                f"No existe la unidad de medida {customs_code}"
                " en el catálogo de Unidades de Medida de la Aduana Mex."
            ),
            solution=["Actualizar sus Catálogos Fijos o llamar a su proveedor."],
            code="UNIMEDIDA",
        )
        return

    # ── 4. Verificar que tenga UnidadSCAII asignada ──────────────────────────
    scaii_unit = customs_uom.a76_unit_code or ""
    if not scaii_unit:
        errors.add_error(
            field=f"line[{line.line_number}].unit_of_measure",
            message=(
                f"No tiene asignada la U.M. Equivalente SCAII la unidad de medida "
                f"{customs_code} en el catálogo de Unidades de Medida de la Aduana Mex."
            ),
            solution=["Actualizar sus Catálogos Fijos o llamar a su proveedor."],
            code="UNIMEDIDA",
        )
        return

    # ── 5. Calcular cantidad UMA ──────────────────────────────────────────────
    line_qty = Decimal(str(line.quantity.quantity or 0)) if line.quantity else Decimal(0)
    cant_uma = Decimal(0)

    if line_um_code == scaii_unit:
        cant_uma = line_qty
    else:
        multi_divide, factor_conv = _get_unit_equivalence(
            db, line_um_code, scaii_unit, tenant_id, company_id
        )

        if multi_divide == "M":
            cant_uma = line_qty * factor_conv
        elif multi_divide == "D":
            cant_uma = line_qty / factor_conv if factor_conv else Decimal(0)
        else:
            errors.add_error(
                field=f"line[{line.line_number}].unit_of_measure",
                message=(
                    f"No hay equivalencia entre la U.M. Partida: {line_um_code}"
                    f" y la U.M. Aduana {scaii_unit}."
                ),
                solution=[
                    "Capturar su equivalencia en el Catálogo de Conversiones "
                    "o configurar la U.M.Aduana correcta en la U.M. Comercial."
                ],
                code="EQUIVALENCIA",
            )
            return

    # ── 6. Escribir resultados en la partida ──────────────────────────────────
    if line.quantity:
        line.quantity.quantity_uma = cant_uma
    line.uma_key = customs_code
