"""Linear interpolation: dipstick height (mm) → volume (litres) via kalibrasi table."""
from decimal import Decimal


def interpolate_volume(height_mm: Decimal, kalibrasi_rows: list) -> Decimal:
    """
    Linear interpolation between two nearest calibration points.

    kalibrasi_rows: list of KalibrasiTangki ORM objects sorted by tinggi_mm ascending.
    Both height_mm and tinggi_mm are in mm — no unit conversion needed.

    Raises ValueError if:
      - height_mm < 0
      - height_mm > max calibration height (out of range)
      - kalibrasi_rows is empty
    Returns Decimal volume in litres.
    """
    if not kalibrasi_rows:
        raise ValueError("Tabel kalibrasi kosong — tidak dapat menghitung volume")

    if height_mm < Decimal("0"):
        raise ValueError(f"Tinggi dipstick tidak boleh negatif: {height_mm} mm")

    # Sort rows by tinggi_mm (should already be sorted, but be safe)
    rows = sorted(kalibrasi_rows, key=lambda r: r.tinggi_mm)

    min_mm = rows[0].tinggi_mm
    max_mm = rows[-1].tinggi_mm

    if height_mm > max_mm:
        raise ValueError(
            f"Tinggi dipstick {height_mm} mm melebihi batas maksimum "
            f"tabel kalibrasi ({max_mm} mm). Periksa pembacaan dipstick."
        )

    # Exact match
    for row in rows:
        if row.tinggi_mm == height_mm:
            return Decimal(str(row.volume_liter))

    # Below minimum → return 0 (essentially empty)
    if height_mm < min_mm:
        return Decimal("0")

    # Linear interpolation between two surrounding points
    lower = None
    upper = None
    for row in rows:
        if row.tinggi_mm <= height_mm:
            lower = row
        elif row.tinggi_mm > height_mm and upper is None:
            upper = row
            break

    if lower is None or upper is None:
        return Decimal(str(rows[-1].volume_liter))

    h1 = Decimal(str(lower.tinggi_mm))
    h2 = Decimal(str(upper.tinggi_mm))
    v1 = Decimal(str(lower.volume_liter))
    v2 = Decimal(str(upper.volume_liter))

    fraction = (height_mm - h1) / (h2 - h1)
    volume = v1 + (v2 - v1) * fraction

    return volume.quantize(Decimal("0.001"))
