from __future__ import annotations

import logging
from dataclasses import dataclass
from decimal import Decimal, ROUND_CEILING

logger = logging.getLogger(__name__)


def parse_boleta_qr_text(qr_texto: str) -> dict[str, int | str] | None:
    if not qr_texto:
        return None

    parts = [p.strip() for p in qr_texto.split("|") if p.strip()]
    data: dict[str, int | str] = {}
    for p in parts:
        if ":" not in p:
            continue
        k, v = p.split(":", 1)
        k = k.strip()
        v = v.strip()
        if not k or not v:
            continue
        if k == "zafra":
            try:
                data["zafra_id"] = int(v)
            except ValueError:
                return None
        elif k == "folio":
            data["folio"] = v

    if "zafra_id" in data and "folio" in data:
        return data
    return None


@dataclass(frozen=True)
class QualityDeductionResult:
    parametro_id: int
    parametro_nombre: str
    kg_por_tonelada: Decimal
    kg_total: Decimal


@dataclass(frozen=True)
class QualityBonusResult:
    parametro_id: int
    parametro_nombre: str
    monto_por_tonelada: Decimal
    monto_total: Decimal


def compute_quality_deductions(*, parametros_resultado, peso_bruto_kg: Decimal, castigos_por_parametro: dict[int, list]):
    peso_bruto_kg = Decimal(peso_bruto_kg)
    toneladas_bruto = (peso_bruto_kg / Decimal("1000")).quantize(Decimal("0.0001"))

    logger.info(
        "compute_quality_deductions: start peso_bruto_kg=%s toneladas_bruto=%s parametros_resultado_type=%s",
        str(peso_bruto_kg),
        str(toneladas_bruto),
        type(parametros_resultado).__name__,
    )

    parametros_considerados: list[str] = []
    rechazos: list[dict] = []
    deducciones: list[QualityDeductionResult] = []
    bonos_por_ton: list[tuple[int, str, Decimal]] = []

    for pr in parametros_resultado:
        p = getattr(pr, "parametro", None)
        if not p:
            continue
        valor = getattr(pr, "valor", None)
        if valor is None:
            continue

        rows = castigos_por_parametro.get(int(p.id)) or []
        if not rows:
            continue

        parametros_considerados.append(p.nombre)

        v = Decimal(valor)
        selected = None
        for r in rows:
            limite = getattr(r, "limite_superior", None)
            if limite is None:
                continue
            if v <= Decimal(limite):
                selected = r
                break

        if selected is None or getattr(selected, "es_rechazo", False):
            rechazos.append({"parametro": p.nombre, "valor": str(valor)})
            continue

        kg_por_ton = Decimal(getattr(selected, "descontar_kg_por_tonelada", 0) or 0)
        if kg_por_ton > 0:
            kg_total = (kg_por_ton * toneladas_bruto).quantize(Decimal("0.01"))
            deducciones.append(
                QualityDeductionResult(
                    parametro_id=p.id,
                    parametro_nombre=p.nombre,
                    kg_por_tonelada=kg_por_ton.quantize(Decimal("0.01")),
                    kg_total=kg_total,
                )
            )

        monto_por_ton = Decimal(getattr(selected, "bonificar_por_tonelada", 0) or 0)
        if monto_por_ton > 0:
            bonos_por_ton.append((p.id, p.nombre, monto_por_ton.quantize(Decimal("0.01"))))

    total_deducido_kg = sum([d.kg_total for d in deducciones], Decimal("0")).quantize(Decimal("0.01"))
    peso_neto_kg = peso_bruto_kg - total_deducido_kg
    if peso_neto_kg < 0:
        peso_neto_kg = Decimal("0")
    toneladas_neto = (peso_neto_kg / Decimal("1000")).quantize(Decimal("0.0001"))

    bonificaciones: list[QualityBonusResult] = []
    for pid, nombre, monto_por_ton in bonos_por_ton:
        monto_total = (Decimal(monto_por_ton) * toneladas_neto).quantize(Decimal("0.01"))
        if monto_total <= 0:
            continue
        bonificaciones.append(
            QualityBonusResult(
                parametro_id=pid,
                parametro_nombre=nombre,
                monto_por_tonelada=Decimal(monto_por_ton).quantize(Decimal("0.01")),
                monto_total=monto_total,
            )
        )

    total_bonificado = sum([b.monto_total for b in bonificaciones], Decimal("0")).quantize(Decimal("0.01"))

    logger.info(
        "compute_quality_deductions: end parametros_considerados=%s deducciones_count=%s rechazos_count=%s bonificaciones_count=%s",
        len(parametros_considerados),
        len(deducciones),
        len(rechazos),
        len(bonificaciones),
    )

    return {
        "parametros_considerados": parametros_considerados,
        "peso_bruto_kg": peso_bruto_kg,
        "toneladas_bruto": toneladas_bruto,
        "deducciones": deducciones,
        "total_deducido_kg": total_deducido_kg,
        "peso_neto_kg": peso_neto_kg,
        "toneladas_neto": toneladas_neto,
        "bonificaciones": bonificaciones,
        "total_bonificado": total_bonificado,
        "rechazos": rechazos,
    }
