"""
REGISTRA_DESCARGA_IMPORTACION
Updates the import line items (temporary or definitive) with the returned
quantities and values consumed by this export invoice.

For each entry in ``to_discharge`` (QSaldoActual in the legacy) the routine:
  · Looks up the source import invoice header (TEM → QFacImp, DEF → QFacImpDef).
  · Looks up the corresponding import line item.
  · Increments value_returned_mxn, value_returned_usd on the import line's
    financial sub-record.
  · For TEM invoices, also calculates vat_used_mxn / vat_used_usd when the
    import invoice date is on or after 2014-12-31 (Clarion date 78165).

Legacy equivalent
-----------------
Loop QSaldoActual:
    If TEM → fetch QFacImp + QEqiMaq, update CantRetornada, ValorRetornadoMN/ME,
             ValorIVAMNUsado / ValorIVAMEUsado
    Else   → fetch QFacImpDef + QEqiDef, update CantRetornada, ValorRetornadoMN/ME
"""

import datetime
from decimal import Decimal
from typing import List, Optional

from sqlalchemy.orm import Session, joinedload

from api.v1.modules.a76.invoices.models import InvoiceHeader
from api.v1.modules.a76.items.models import LineItem
from .discharge_types import DownloadEntry

# Cutoff date: Clarion day 78165 ≈ 2014-12-31
_VAT_CUTOFF = datetime.date(2014, 12, 31)


# ---------------------------------------------------------------------------
# Private helpers
# ---------------------------------------------------------------------------

def _fetch_import_invoice(
    db: Session,
    invoice_number: str,
    export_invoice: InvoiceHeader,
) -> Optional[InvoiceHeader]:
    """Return the import InvoiceHeader that matches *invoice_number*."""
    return (
        db.query(InvoiceHeader)
        .filter(
            InvoiceHeader.invoice_number == invoice_number,
            InvoiceHeader.tenant_id == export_invoice.tenant_id,
            InvoiceHeader.company_id == export_invoice.company_id,
        )
        .first()
    )


def _fetch_import_line(
    db: Session,
    invoice_id: int,
    line_number: int,
    tenant_id: int,
    company_id: int,
) -> Optional[LineItem]:
    """Return the LineItem for *invoice_id* / *line_number*, with financial and quantity loaded."""
    return (
        db.query(LineItem)
        .options(
            joinedload(LineItem.quantity),
            joinedload(LineItem.financial),
        )
        .filter(
            LineItem.invoice_id == invoice_id,
            LineItem.line_number == line_number,
            LineItem.tenant_id == tenant_id,
            LineItem.company_id == company_id,
        )
        .first()
    )


# ---------------------------------------------------------------------------
# Public entry point
# ---------------------------------------------------------------------------

def register_import_discharge(
    db: Session,
    export_invoice: InvoiceHeader,
    to_discharge: List[DownloadEntry],
) -> None:
    """
    REGISTRA_DESCARGA_IMPORTACION
    Accumulates discharged quantities and values back onto the source import
    line items (temporal or definitive).

    Parameters
    ----------
    db              : active SQLAlchemy session
    export_invoice  : the export invoice being processed
    to_discharge    : list of DownloadEntry records (QSaldoActual equivalent);
                      each entry's ``quantity`` holds the amount consumed
                      (QSaldo:CantUsada in the legacy).
    """
    # Sort mirrors the Clarion: Sort(QSaldoActual, -Procedencia, FacturaImpo, LineaImpo)
    # (descending procedencia puts 'TEM' before 'DEF' alphabetically reversed)
    sorted_entries = sorted(
        to_discharge,
        key=lambda e: (e.origin_procedure, e.import_invoice, e.import_line),
        reverse=False,
    )

    for entry in sorted_entries:
        qty_used = entry.quantity  # CantUsada — full entry qty consumed

        if not entry.import_invoice or entry.import_line == 0:
            continue

        # ── Fetch source import invoice header ───────────────────────────────
        import_invoice = _fetch_import_invoice(db, entry.import_invoice, export_invoice)
        if import_invoice is None:
            continue

        # ── Fetch source import line item ─────────────────────────────────────
        import_line = _fetch_import_line(
            db,
            import_invoice.id,
            entry.import_line,
            export_invoice.tenant_id,
            export_invoice.company_id,
        )
        if import_line is None:
            continue

        # ── Calculate proportional values ─────────────────────────────────────
        # value_returned = qty_used * (line_value / line_qty)
        fin = import_line.financial
        qty_rec = import_line.quantity

        if fin is None or qty_rec is None:
            continue

        original_qty = qty_rec.quantity or Decimal(0)
        if original_qty == 0:
            continue

        value_mn = Decimal(str(fin.value_mxn or 0))
        value_usd = Decimal(str(fin.value_usd or 0))

        returned_mn  = qty_used * value_mn  / original_qty
        returned_usd = qty_used * value_usd / original_qty

        # ── Accumulate returned value ──────────────────────────────────────────
        fin.value_returned_mxn = (fin.value_returned_mxn or Decimal(0)) + returned_mn
        fin.value_returned_usd = (fin.value_returned_usd or Decimal(0)) + returned_usd

        # ── VAT used (TEM only, and only for invoices on/after cutoff date) ───
        # Clarion: IF EqiFim:FechaFactura > 78165 (≈ 2014-12-31)
        if entry.origin_procedure == "TEM":
            inv_date = import_invoice.invoice_date
            if isinstance(inv_date, datetime.datetime):
                inv_date = inv_date.date()

            if inv_date and inv_date >= _VAT_CUTOFF:
                iva_factor = Decimal(0)
                if import_invoice.financials and import_invoice.financials.iva_factor:
                    iva_factor = Decimal(str(import_invoice.financials.iva_factor))

                fin.vat_used_mxn = (returned_mn  * iva_factor) / 100
                fin.vat_used_usd = (returned_usd * iva_factor) / 100
            else:
                fin.vat_used_mxn = Decimal(0)
                fin.vat_used_usd = Decimal(0)
