from decimal import Decimal
from typing import List

from api.v1.modules.a76.invoices.models import Currency, InvoiceHeader
from api.v1.modules.a76.items.models import LineItem


def assign_values_iva_lines(
    invoice: InvoiceHeader,
    lines: List[LineItem],
) -> None:
    """
    ASIGNAVALORES_IVA_PARTIDA
    Asigna valores por partida para IMPO DEFINITIVA / COMPRAS MEXICANAS
    calculando subtotal + IVA + total en ME/MN/MC.

    Nota:
    - Los contadores legacy CantRetornada/CantRetornadaTemp ya no existen.
    - La trazabilidad de saldos vive en balance_movement + discharges.
    """
    if not invoice.financials:
        return

    currency = invoice.financials.currency
    tc = Decimal(str(invoice.financials.exchange_rate or 0))
    tc_mm = Decimal(str(invoice.financials.exchange_rate_mm or 0))
    iva_factor = Decimal(str(invoice.financials.iva_factor or 0))

    for line in lines:
        fin = line.financial
        qty_rec = line.quantity
        if fin is None or qty_rec is None:
            continue

        qty = Decimal(str(qty_rec.quantity or 0))
        capture = Decimal(str(fin.unit_cost_capture or 0))
        if qty <= 0:
            continue

        if currency == Currency.FOREIGN:  # ME
            # ME base
            fin.unit_cost_usd = capture
            fin.sub_import_value_usd = capture * qty
            fin.vat_usd = fin.sub_import_value_usd * iva_factor / 100
            fin.value_usd = fin.sub_import_value_usd + fin.vat_usd

            # MN converted from ME
            fin.unit_cost_mxn = capture * tc
            fin.sub_import_value_mxn = fin.unit_cost_mxn * qty
            fin.vat_mxn = fin.sub_import_value_mxn * iva_factor / 100
            fin.value_mxn = fin.sub_import_value_mxn + fin.vat_mxn

            # MC mirrors capture currency in legacy
            fin.unit_cost_mc = capture
            fin.sub_import_value_mc = capture * qty
            fin.vat_mc = fin.sub_import_value_mc * iva_factor / 100
            fin.value_mc = fin.sub_import_value_mc + fin.vat_mc

        elif currency == Currency.LOCAL:  # MN
            # MN base
            fin.unit_cost_mxn = capture
            fin.sub_import_value_mxn = capture * qty
            fin.vat_mxn = fin.sub_import_value_mxn * iva_factor / 100
            fin.value_mxn = fin.sub_import_value_mxn + fin.vat_mxn

            # ME converted from MN
            fin.unit_cost_usd = (capture / tc) if tc else Decimal(0)
            fin.sub_import_value_usd = fin.unit_cost_usd * qty
            fin.vat_usd = fin.sub_import_value_usd * iva_factor / 100
            fin.value_usd = fin.sub_import_value_usd + fin.vat_usd

            # MC mirrors capture currency in legacy
            fin.unit_cost_mc = capture
            fin.sub_import_value_mc = capture * qty
            fin.vat_mc = fin.sub_import_value_mc * iva_factor / 100
            fin.value_mc = fin.sub_import_value_mc + fin.vat_mc

        elif currency == Currency.MANUAL:  # MC
            # ME from MC * tc_mm
            fin.unit_cost_usd = capture * tc_mm
            fin.sub_import_value_usd = fin.unit_cost_usd * qty
            fin.vat_usd = fin.sub_import_value_usd * iva_factor / 100
            fin.value_usd = fin.sub_import_value_usd + fin.vat_usd

            # MN from ME * tc
            fin.unit_cost_mxn = fin.unit_cost_usd * tc
            fin.sub_import_value_mxn = fin.unit_cost_mxn * qty
            fin.vat_mxn = fin.sub_import_value_mxn * iva_factor / 100
            fin.value_mxn = fin.sub_import_value_mxn + fin.vat_mxn

            # MC base
            fin.unit_cost_mc = capture
            fin.sub_import_value_mc = capture * qty
            fin.vat_mc = fin.sub_import_value_mc * iva_factor / 100
            fin.value_mc = fin.sub_import_value_mc + fin.vat_mc


def assign_values_invoice_totals(
    invoice: InvoiceHeader,
    lines: List[LineItem],
) -> None:
    """
    ASIGNAVALORES_FACTURA
    Totaliza cantidades, pesos y valores/IVA en encabezado para IMPO DEF/MEX.
    """
    if not invoice.financials:
        return

    total_qty = Decimal(0)
    total_net = Decimal(0)
    total_gross = Decimal(0)
    total_packages = 0

    total_val_mn = Decimal(0)
    total_val_me = Decimal(0)
    total_val_mc = Decimal(0)
    total_iva_mn = Decimal(0)
    total_iva_me = Decimal(0)
    total_iva_mc = Decimal(0)
    total_sub_mn = Decimal(0)
    total_sub_me = Decimal(0)
    total_sub_mc = Decimal(0)

    for line in lines:
        q = line.quantity
        f = line.financial
        if q:
            total_qty += Decimal(str(q.quantity or 0))
            total_net += Decimal(str(q.net_weight or 0))
            total_gross += Decimal(str(q.gross_weight or 0))
            total_packages += int(q.package_quantity or 0)
        if f:
            total_val_mn += Decimal(str(f.value_mxn or 0))
            total_val_me += Decimal(str(f.value_usd or 0))
            total_val_mc += Decimal(str(f.value_mc or 0))
            total_iva_mn += Decimal(str(f.vat_mxn or 0))
            total_iva_me += Decimal(str(f.vat_usd or 0))
            total_iva_mc += Decimal(str(f.vat_mc or 0))
            total_sub_mn += Decimal(str(f.sub_import_value_mxn or 0))
            total_sub_me += Decimal(str(f.sub_import_value_usd or 0))
            total_sub_mc += Decimal(str(f.sub_import_value_mc or 0))

    fin = invoice.financials
    fin.total_quantity = float(total_qty)
    fin.net_weight = float(total_net)
    fin.gross_weight = float(total_gross)
    fin.total_packages = total_packages

    fin.value_mn = float(total_val_mn)
    fin.value_me = float(total_val_me)
    fin.value_mc = float(total_val_mc)

    fin.iva_mn = float(total_iva_mn)
    fin.iva_me = float(total_iva_me)
    fin.iva_mc = float(total_iva_mc)

    # No existe subtotal a nivel encabezado en el modelo actual.
    # Se conserva en partidas (sub_import_value_*), de donde se agrega cuando se necesite.
    _ = (total_sub_mn, total_sub_me, total_sub_mc)
