"""Business case maths + exports."""

from __future__ import annotations

import pytest

from tokencalc.business_case import build_business_case, npv, payback_years
from tokencalc.defaults import (
    CTM_DEFAULT_FEATURE_SCOPES,
    CTM_DEFAULT_SITES,
    CTM_DEFAULT_TAKEOUTS,
    DEFAULT_METERS,
    DEFAULT_PRICING,
)
from tokencalc.exports import (
    export_excel,
    scenario_state_from_json,
    scenario_state_to_json,
)


def test_npv_hand_check():
    """100/yr for 3 years @ 8%: 92.593 + 85.734 + 79.383 = 257.710."""
    assert npv([100, 100, 100], 0.08) == pytest.approx(257.710, abs=0.001)


def test_payback_interpolation():
    # -100 in Y1, +200 in Y2 → breakeven halfway through Y2 = 1.5 years
    assert payback_years([-100, 200, 0]) == pytest.approx(1.5)
    assert payback_years([-100, -100, -100]) is None
    assert payback_years([50, 50, 50]) == pytest.approx(0.0)


def _case(scenario="realistic", **kw):
    return build_business_case(
        CTM_DEFAULT_SITES, CTM_DEFAULT_FEATURE_SCOPES, DEFAULT_METERS,
        DEFAULT_PRICING, CTM_DEFAULT_TAKEOUTS, scenario, **kw,
    )


def test_business_case_shape():
    case = _case()
    assert set(case) == {
        "cost_by_year", "benefit_by_year", "takeouts_by_year",
        "net_by_year", "cumulative_net", "npv",
        "payback_period_years", "roi_3yr",
    }
    for key in ("cost_by_year", "benefit_by_year", "net_by_year"):
        assert {"Y1", "Y2", "Y3"} <= set(case[key].columns)


def test_net_consistency():
    """NET row must equal benefits + takeouts − costs, per year."""
    case = _case()
    nb = case["net_by_year"].set_index("line")
    for y in ("Y1", "Y2", "Y3"):
        assert nb.loc["NET", y] == pytest.approx(
            nb.loc["TOTAL BENEFITS", y]
            + nb.loc["TOTAL TAKEOUTS", y]
            - nb.loc["TOTAL COSTS", y]
        )
    # cumulative is a running sum of NET
    assert nb.loc["Cumulative net", "Y3"] == pytest.approx(
        sum(nb.loc["NET", y] for y in ("Y1", "Y2", "Y3"))
    )


def test_npv_matches_net_rows():
    case = _case()
    nb = case["net_by_year"].set_index("line")
    net = [nb.loc["NET", y] for y in ("Y1", "Y2", "Y3")]
    assert case["npv"] == pytest.approx(npv(net, 0.08))


def test_three_scenarios_distinct():
    npvs = {s: _case(s)["npv"] for s in ("floor", "realistic", "stretch")}
    assert len({round(v) for v in npvs.values()}) == 3
    assert npvs["floor"] < npvs["realistic"] < npvs["stretch"]


def test_implementation_amortization():
    base = _case()
    with_impl = _case(implementation_cost=900_000)
    nb, nb2 = (
        c["net_by_year"].set_index("line") for c in (base, with_impl)
    )
    for y in ("Y1", "Y2", "Y3"):
        assert nb2.loc["TOTAL COSTS", y] == pytest.approx(
            nb.loc["TOTAL COSTS", y] + 300_000
        )


def test_excel_export_readable(tmp_path):
    case = _case()
    path = export_excel(
        {
            "Business Case": case["net_by_year"],
            "Costs": case["cost_by_year"],
            "Benefits": case["benefit_by_year"],
        },
        tmp_path / "ctm.xlsx",
    )
    import openpyxl

    wb = openpyxl.load_workbook(path)
    assert set(wb.sheetnames) == {"Business Case", "Costs", "Benefits"}


def test_scenario_json_roundtrip(tmp_path):
    p = tmp_path / "state.json"
    scenario_state_to_json(
        CTM_DEFAULT_SITES, CTM_DEFAULT_TAKEOUTS, CTM_DEFAULT_FEATURE_SCOPES, p
    )
    sites, takeouts, scopes, _rollout = scenario_state_from_json(p)
    assert [s.site_name for s in sites] == [s.site_name for s in CTM_DEFAULT_SITES]
    assert takeouts[0].annual_cost == CTM_DEFAULT_TAKEOUTS[0].annual_cost
    assert scopes[0].adoption_curve == CTM_DEFAULT_FEATURE_SCOPES[0].adoption_curve
