from decimal import Decimal
from typing import List

from sqlalchemy.orm import Session

from api.v1.modules.a76.rule_octave.balances.models import OctaveBalance
from api.v1.modules.a76.rule_octave.fractions.models import FractionRuleOctave


def borra_saldos_regla_octava(
    db: Session,
    invoice_import: str,
    tenant_id: str,
    company_id: str,
    sql_errors: list,
) -> None:
    """
    Revierte los saldos de Regla Octava registrados al procesar una factura de
    importación temporal.
    Paridad: BORRASALDOS_REGLA_OCTAVA (Clarion SCAII).

    Por cada registro en SSaldosReglaOctava (OctaveBalance) con origin='TEM' y
    system='SCAF' que corresponda a la factura:
      1. Resta de vuelta la cantidad y el valor en GFracROctava (FractionRuleOctave).
      2. Elimina el registro de OctaveBalance.

    Los errores de actualización se acumulan en sql_errors como dicts con las
    claves 'consecutive' y 'error'.
    """
    consecutive_ref = [0]

    balances: List[OctaveBalance] = (
        db.query(OctaveBalance)
        .filter(
            OctaveBalance.tenant_id == tenant_id,
            OctaveBalance.company_id == company_id,
            OctaveBalance.invoice_import == invoice_import,
            OctaveBalance.origin == "TEM",
            OctaveBalance.system == "SCAF",
        )
        .all()
    )

    for balance in balances:
        fra_oct = (
            db.query(FractionRuleOctave)
            .filter(
                FractionRuleOctave.tenant_id == tenant_id,
                FractionRuleOctave.company_id == company_id,
                FractionRuleOctave.permission == balance.octave_permit,
                FractionRuleOctave.line == balance.line,
            )
            .first()
        )

        # REGRESAR EL SALDO AL PERMISO DE REGLA OCTAVA
        # Si el permiso no existe (TryFetch falla en Clarion), se omite el PUT
        # pero el DELETE del saldo se ejecuta de todas formas — paridad Clarion.
        if fra_oct is not None:
            qty_back = balance.quantity_stock or Decimal(0)
            val_back = balance.value_me or Decimal(0)

            fra_oct.quantity_used = max(
                Decimal(0),
                (fra_oct.quantity_used or Decimal(0)) - qty_back,
            )
            fra_oct.value_used = max(
                Decimal(0),
                (fra_oct.value_used or Decimal(0)) - val_back,
            )

            try:
                db.flush([fra_oct])
            except Exception as exc:
                consecutive_ref[0] += 1
                sql_errors.append({
                    "consecutive": consecutive_ref[0],
                    "error": (
                        f"Error al regresar el Cupo en (Permiso de Regla Octava) {exc}"
                    ),
                })

        # DELETE(SSaldosReglaOctava) — siempre se intenta, igual que en Clarion
        try:
            db.delete(balance)
            db.flush([balance])
        except Exception as exc:
            consecutive_ref[0] += 1
            sql_errors.append({
                "consecutive": consecutive_ref[0],
                "error": (
                    f"Error al Eliminar en (SSaldosReglaOctava) {exc}"
                ),
            })
