"""
REVISA_SERIES_EXISTA
Verifies that every export series marked for discharge (discharge=True / Marca=1)
references a row that actually exists in the corresponding import invoice line.

Clarion mapping
---------------
QSeriesExpo   → Serie  (line_item_id = export LineItem.id)
QSeriesImpo   → Serie  (line_item_id = import LineItem.id, for TEM invoices)
QSeriesDef    → Serie  (line_item_id = import LineItem.id, for DEF invoices)

SerExpo.Marca         = 1       → Serie.discharge = True
SerExpo.LineaSerieImpo          → Serie.serie_row
SerImp.Renglon / SerDef.Renglon → Serie.row  (on the import side)

Logic
-----
For each export serie with discharge=True on this line, check that
``serie_row`` exists as a ``row`` in the series of the referenced
import invoice line.  If it does not → error.

The check differs by origin_procedure:
  TEM → look in import invoice (InvoiceType='TEM')
  DEF → look in import invoice (InvoiceType='DEF')
"""

from typing import List, Set

from sqlalchemy import select
from sqlalchemy.orm import Session

from api.v1.modules.a76.invoices.models import InvoiceHeader
from api.v1.modules.a76.items.models import LineItem
from api.v1.modules.a76.items.series.models import Serie
from api.v1.modules.a76.invoices.exports.process.sub_process.discharge_types import (
    DownloadEntry,
)
from core.exceptions import ErrorCollector


def review_series_exist(
    db: Session,
    invoice: InvoiceHeader,
    line: LineItem,
    entry: DownloadEntry,
    errors: ErrorCollector,
) -> None:
    """
    REVISA_SERIES_EXISTA
    Checks that every export serie marked for discharge on ``line`` references
    an import serie row that actually exists in the import invoice line.

    Parameters
    ----------
    db      : active SQLAlchemy session
    invoice : the export invoice being processed
    line    : the export LineItem whose series are being validated
    entry   : the DownloadEntry for this line (provides import_invoice / import_line)
    errors  : shared error collector
    """
    # ── 1. Export series with discharge=True on this line ────────────────────
    export_series: List[Serie] = (
        db.execute(
            select(Serie).where(
                Serie.line_item_id == line.id,
                Serie.discharge == True,  # noqa: E712 — SQLAlchemy requires ==
            )
        )
        .scalars()
        .all()
    )

    if not export_series:
        return

    # ── 2. Resolve the import LineItem ───────────────────────────────────────
    invoice_type_filter = entry.origin_procedure.upper()  # 'TEM' or 'DEF'

    import_line_id: int | None = (
        db.execute(
            select(LineItem.id)
            .join(InvoiceHeader, LineItem.invoice_id == InvoiceHeader.id)
            .where(
                InvoiceHeader.tenant_id == invoice.tenant_id,
                InvoiceHeader.invoice_number == entry.import_invoice,
                InvoiceHeader.invoice_type == invoice_type_filter,
                LineItem.line_number == entry.import_line,
            )
        )
        .scalar_one_or_none()
    )

    if import_line_id is None:
        # The import line itself was not found — already caught by fill_available_balances,
        # but add a targeted error here as well.
        errors.add_error(
            field=f"line[{line.line_number}].series",
            message=(
                f"No se encontró la línea {entry.import_line} de la factura de "
                f"importación '{entry.import_invoice}' para validar las series."
            ),
            solution=["Verificar que la factura y línea de importación existen y están procesadas."],
            code="IMPORT_LINE_NOT_FOUND_FOR_SERIES",
        )
        return

    # ── 3. Fetch the set of valid import serie rows ───────────────────────────
    valid_rows: Set[int] = set(
        db.execute(
            select(Serie.row).where(
                Serie.line_item_id == import_line_id,
            )
        )
        .scalars()
        .all()
    )

    # ── 4. Validate each export serie ────────────────────────────────────────
    invoice_type_label = (
        "Impo. Tem." if invoice_type_filter == "TEM" else "Impo. Def."
    )
    invoice_type_code = (
        "FAC_IMPO_TEM" if invoice_type_filter == "TEM" else "FAC_IMPO_DEF"
    )

    for serie in export_series:
        ref_row = serie.serie_row

        if ref_row is None or ref_row not in valid_rows:
            errors.add_error(
                field=f"line[{line.line_number}].series[{serie.row}]",
                message=(
                    f"La Línea: {serie.serie_row} "
                    f"(Serie: {serie.serial_numbers or ''}) "
                    f"no existe en la Factura de {invoice_type_label}: "
                    f"'{entry.import_invoice}' con Línea: {entry.import_line}."
                ),
                solution=[
                    "Capturar un número de Serie que exista en la Factura "
                    "y Línea a Descargar de Importación."
                ],
                code=invoice_type_code,
                value={
                    "export_serie_row": serie.row,
                    "serie_row": ref_row,
                    "import_invoice": entry.import_invoice,
                    "import_line": entry.import_line,
                },
            )
