"""Variance and tolerance helpers (CONTRACT §5).

``variance = round(planned - invoiced, rounding)`` (ex-VAT). A pairing is within
tolerance when ``abs(variance) <= max(ABS_TOLERANCE, planned * REL_TOLERANCE)``.
"""

from __future__ import annotations


def variance(planned: float, invoiced: float, rounding: int = 2) -> float:
    """Return ``planned - invoiced`` rounded to ``rounding`` decimals."""
    return round(float(planned) - float(invoiced), rounding)


def tolerance_band(planned: float, abs_tol: float, rel_tol: float) -> float:
    """The allowed absolute variance for a planned amount."""
    return max(float(abs_tol), abs(float(planned)) * float(rel_tol))


def within_tolerance(
    planned: float,
    invoiced: float,
    abs_tol: float,
    rel_tol: float,
    rounding: int = 2,
) -> bool:
    """True when the rounded variance falls inside the tolerance band."""
    v = variance(planned, invoiced, rounding)
    return abs(v) <= tolerance_band(planned, abs_tol, rel_tol)
