from __future__ import annotations

from decimal import Decimal

import pytest

from app.clinical_pipeline.domain import MonetaryAmount
from app.llm.renderers.clinical_documents import render_factura_html
from app.services.factura_deterministic import (
    build_factura_structured,
    reconcile_factura_financials,
)


@pytest.mark.parametrize(
    ("raw", "expected"),
    [
        ("$185,700.00", Decimal("185700.00")),
        ("$185.700,00", Decimal("185700.00")),
        ("185700.00", Decimal("185700.00")),
        ("185700,00", Decimal("185700.00")),
        ("-$1,234.50", Decimal("-1234.50")),
        ("($1.234,50)", Decimal("-1234.50")),
        ("0", Decimal("0.00")),
        ("1,234", Decimal("1234.00")),
        ("1.234", Decimal("1234.00")),
    ],
)
def test_monetary_amount_normalizes_supported_formats(raw: str, expected: Decimal) -> None:
    assert MonetaryAmount(amount=raw).amount == expected


@pytest.mark.parametrize("raw", ["", "importe", "$1,23,4", "$12.3456", "1.234,567"])
def test_monetary_amount_rejects_invalid_or_ambiguous_formats(raw: str) -> None:
    assert MonetaryAmount.try_parse(raw) is None


def _line(
    index: int,
    *,
    quantity: str = "1.00",
    unit_value: str = "$100.00",
    total: str = "$100.00",
    rate_suffix: str = "",
) -> dict[str, str]:
    return {
        "fecha_servicio": "2024-05-09",
        "codigo_facturacion": f"COD{index}{rate_suffix}",
        "codigo_referencia": f"REF{index}",
        "descripcion": f"Servicio anonimizado {index}",
        "categoria": "otros_servicios",
        "cantidad": quantity,
        "valor_unitario": unit_value,
        "total": total,
    }


def test_reconciliation_corrects_lines_discounts_copayments_and_final_total() -> None:
    result = reconcile_factura_financials(
        [
            _line(1, quantity="2", unit_value="$185,700.00", total="$371.40"),
            _line(2, unit_value="$10.00", total="$10.01"),
        ],
        {
            "total_servicios": "$381.41",
            "descuentos": "$1,000.00",
            "copagos": "$400.00",
            "valor_total_factura": "$0.00",
        },
    )

    assert result.lineas_canonicas[0]["cantidad"] == "2.00"
    assert result.lineas_canonicas[0]["total"] == "$371,400.00"
    assert result.lineas_canonicas[1]["total"] == "$10.01"
    assert result.resumen_financiero["total_servicios"] == "$371,410.01"
    assert result.resumen_financiero["valor_total_factura"] == "$370,010.01"
    assert result.validacion_financiera["estado"] == "reconciliada"
    assert result.validacion_financiera["lineas_corregidas"] == 1


def test_reconciliation_infers_missing_adjustments_only_when_extracted_totals_match() -> None:
    reconciled = reconcile_factura_financials(
        [_line(1)],
        {"total_servicios": "$100.00", "valor_total_factura": "$100.00"},
    )
    unresolved = reconcile_factura_financials(
        [_line(1)],
        {"total_servicios": "$100.00", "valor_total_factura": "$90.00"},
    )

    assert reconciled.validacion_financiera["estado"] == "reconciliada"
    assert reconciled.resumen_financiero["descuentos"] == "$0.00"
    assert reconciled.resumen_financiero["copagos"] == "$0.00"
    assert unresolved.validacion_financiera["estado"] == "no_reconciliada"
    assert "financial_adjustment_missing" in unresolved.validacion_financiera["codigos_calidad"]


def test_reconciliation_preserves_invalid_values_and_marks_quality() -> None:
    line = _line(1, quantity="dos", unit_value="$100.00", total="importe ilegible")
    result = reconcile_factura_financials(
        [line],
        {"total_servicios": "importe ilegible", "descuentos": "$0", "copagos": "$0"},
    )

    assert result.lineas_canonicas[0]["cantidad"] == "dos"
    assert result.lineas_canonicas[0]["total"] == "importe ilegible"
    assert result.resumen_financiero["total_servicios"] == "importe ilegible"
    assert result.validacion_financiera["estado"] == "no_reconciliada"
    assert "financial_line_quantity_invalid" in result.validacion_financiera["codigos_calidad"]
    assert result.validacion_financiera["detalle_lineas"][0]["codigo_facturacion"] == "COD1"
    assert "descripcion" not in result.validacion_financiera["detalle_lineas"][0]


def test_build_groups_same_day_and_rate_using_decimal_quantity_and_calculated_total() -> None:
    first = _line(1, quantity="1.25", unit_value="$185.700,00", total="$1.00")
    second = dict(first, cantidad="0,75", total="$2.00")
    different_rate = dict(first, valor_unitario="$185,701.00", total="$185,701.00")
    current = {
        "dt": "factura",
        "lc": [first, second, different_rate],
        "rf": {"dc": "$0.00", "cg": "$0.00"},
    }

    model, factura_json = build_factura_structured(raw_text="", current_structured=current)

    assert len(model.lineas_canonicas) == 2
    assert model.lineas_canonicas[0].cantidad == "2.00"
    assert model.lineas_canonicas[0].total == "$371,400.00"
    assert model.lineas_canonicas[1].valor_unitario == "$185,701.00"
    assert factura_json["validacion_financiera"]["estado"] == "reconciliada"


def test_anonymized_63_line_regression_reconciles_11_lines_and_all_representations() -> None:
    lines = [
        _line(index, unit_value="$185,700.00", total="$185.70")
        for index in range(11)
    ]
    lines.extend(
        _line(index, unit_value="$100,000.00", total="$100,000.00")
        for index in range(11, 62)
    )
    lines.append(_line(62, unit_value="$942,512.00", total="$942,512.00"))
    current = {
        "dt": "factura",
        "lc": lines,
        "rf": {
            "ts": "$5,791,129.51",
            "dc": "$0.00",
            "cg": "$0.00",
            "vt": "$5,791,129.51",
        },
    }

    model, factura_json = build_factura_structured(raw_text="", current_structured=current)
    rendered = render_factura_html(model)

    validation = factura_json["validacion_financiera"]
    assert len(factura_json["lineas_canonicas"]) == 63
    assert validation["lineas_corregidas"] == 11
    assert validation["estado"] == "reconciliada"
    assert model.resumen_financiero.total_servicios == "$8,085,212.00"
    assert model.resumen_financiero.valor_total_factura == "$8,085,212.00"
    assert factura_json["analisis_financiero"]["total_servicios"] == "$8,085,212.00"
    assert factura_json["servicios_procedimientos"]["otros_servicios"][0]["total"] == "$185,700.00"
    assert "$8,085,212.00" in rendered
