"""Verify rounding vectors are mathematically correct."""

from decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP

import pytest

from finlint.vectors import load_suite


@pytest.fixture(scope="module")
def vectors():
    return load_suite("rounding")


def test_round_001_bankers_rounding(vectors):
    """Banker's rounding: 2.5→2, 3.5→4, 4.5→4."""
    v = vectors[0]
    for val_str, exp_str in zip(v["inputs"]["values"], v["expected"]["results"]):
        result = Decimal(val_str).quantize(Decimal("1"), rounding=ROUND_HALF_EVEN)
        assert result == Decimal(exp_str), f"ROUND_HALF_EVEN({val_str}) = {result}, expected {exp_str}"


def test_round_002_half_up_rounding(vectors):
    """Half-up rounding: 2.5→3, 3.5→4, 4.5→5."""
    v = vectors[1]
    for val_str, exp_str in zip(v["inputs"]["values"], v["expected"]["results"]):
        result = Decimal(val_str).quantize(Decimal("1"), rounding=ROUND_HALF_UP)
        assert result == Decimal(exp_str), f"ROUND_HALF_UP({val_str}) = {result}, expected {exp_str}"


def test_round_003_float_trap(vectors):
    """0.1 + 0.2 with Decimal equals 0.3; with float it doesn't."""
    v = vectors[2]
    ops = v["inputs"]["operands"]
    decimal_result = Decimal(ops[0]) + Decimal(ops[1])
    assert decimal_result == Decimal(v["expected"]["result"])
    # Float version fails
    assert 0.1 + 0.2 != 0.3


def test_round_004_precision_trap(vectors):
    """1.005 rounded to 2dp: Decimal→1.01, float→1.00."""
    v = vectors[3]
    decimal_result = Decimal(v["inputs"]["value"]).quantize(
        Decimal("0.01"), rounding=ROUND_HALF_UP
    )
    assert decimal_result == Decimal(v["expected"]["result"])
    # Float version gives wrong answer
    assert round(1.005, 2) != 1.01


def test_round_005_quantize_idempotent(vectors):
    """quantize(quantize(x)) == quantize(x) for all x."""
    v = vectors[4]
    quant = Decimal("0.01")
    first = Decimal(v["inputs"]["value"]).quantize(quant, rounding=ROUND_HALF_UP)
    second = first.quantize(quant, rounding=ROUND_HALF_UP)
    assert first == second == Decimal(v["expected"]["result"])
