"""
REVISA_TIPOCAMBIO
Validates that the exchange rate captured on the export invoice matches the
rate registered in the exchange-rate catalogue for the invoice date.

Only runs when SisGen:CalValBaseTCPedExpo = 0 (use invoice-date TC, not
pedimento-payment-date TC).  When the flag is 1 the TC is taken from the
pedimento and this check is skipped — that branch is handled in the TODO
for step 7 of main_process.

Clarion mapping
---------------
gtipocambio         → a76.exchange_rate  (ExchangeRate model)
FECHA               → ExchangeRate.date  (cast to DATE for comparison)
VALOR               → ExchangeRate.value
EqiFex:FechaFactura → invoice.invoice_date
EqiFex:TipoCambio   → invoice.financials.exchange_rate
"""

import datetime
from decimal import Decimal
from typing import Optional

from sqlalchemy import cast, Date, select
from sqlalchemy.orm import Session

from api.v1.modules.a76.invoices.models import InvoiceHeader
from api.v1.modules.a76.general_catalogs.exchange_rate.models import ExchangeRate
from core.exceptions import ErrorCollector


def review_exchange_rate(
    db: Session,
    invoice: InvoiceHeader,
    cal_val_base_tc: int,
    errors: ErrorCollector,
) -> None:
    """
    REVISA_TIPOCAMBIO
    Checks that the invoice's exchange rate matches the catalogue value for
    the invoice date.

    Parameters
    ----------
    db      : active SQLAlchemy session
    invoice : the export invoice being processed
    cal_val_base_tc : flag from settings (1 = skip validation as TC comes from pedimento)
    errors  : shared error collector
    """
    if cal_val_base_tc == 1:
        # SKIP: TC is taken from pedimento payment date, resolved in main_process Step 7
        return

    if not invoice.financials:
        return

    invoice_date: datetime.date = (
        invoice.invoice_date.date()
        if hasattr(invoice.invoice_date, "date")
        else invoice.invoice_date
    )

    # Look up the catalogue rate for the invoice date
    catalogue_rate: Optional[ExchangeRate] = db.execute(
        select(ExchangeRate).where(
            ExchangeRate.tenant_id == invoice.tenant_id,
            ExchangeRate.company_id == invoice.company_id,
            cast(ExchangeRate.date, Date) == invoice_date,
        )
    ).scalar_one_or_none()

    if catalogue_rate is None:
        # No rate registered for this date — cannot validate, skip
        # (the Clarion loop simply finds no rows and exits cleanly)
        return

    invoice_tc = Decimal(str(invoice.financials.exchange_rate or 0))
    catalogue_tc = Decimal(str(catalogue_rate.value or 0))

    if invoice_tc != catalogue_tc:
        errors.add_error(
            field="financials.exchange_rate",
            message="No está capturado correctamente el Tipo de Cambio.",
            solution=[
                "Capture o modifique el tipo de cambio que corresponda a la "
                "factura en el catálogo de Tipo de Cambio."
            ],
            code="EXCHANGE_RATE_MISMATCH",
            value={
                "invoice_date": str(invoice_date),
                "invoice_tc": str(invoice_tc),
                "catalogue_tc": str(catalogue_tc),
            },
        )
