"""Reproduce IsMyPayRight's 240 salary-only annual scenarios, version 1.0.

Download pay-rise-2026-27-v1.json into this same folder, then run with Python 3:
    python reproduce-pay-rise-2026-27.py
Uses only Python's standard library; no network access or account is needed.
Not a general payroll calculator. The dataset states exclusions and official sources.
This small reference calculation is separate from the website's calculation engine.
Original analysis/script may be reused with credit and a link to:
https://www.ismypayright.co.uk/guides/1000-pay-rise-after-tax-2026-27
"""
import json
from decimal import Decimal, ROUND_HALF_UP
from pathlib import Path

D = Decimal
PENNY = D("0.01")
# Taxable-income bands, after Personal Allowance; HMRC 2026/27 employer tables.
BANDS = {
    "england": [(37700, "0.20"), (125140, "0.40"), (None, "0.45")],
    "scotland": [(3967, "0.19"), (16956, "0.20"), (31092, "0.21"),
                 (62430, "0.42"), (125140, "0.45"), (None, "0.48")],
}
LOANS = {
    "plan1": (26900, "0.09"), "plan2": (29385, "0.09"),
    "plan4": (33795, "0.09"), "plan5": (25000, "0.09"),
    "postgraduate": (21000, "0.06"),
}


def money(value):
    return D(value).quantize(PENNY, rounding=ROUND_HALF_UP)


def annual(salary, region, plans):
    salary = D(salary)
    allowance = max(D(0), D(12570) - max(D(0), salary - 100000) / 2)
    taxable = max(D(0), salary - allowance)
    tax, lower = D(0), D(0)
    for upper, rate in BANDS[region]:
        upper = taxable if upper is None else D(upper)
        tax += money(max(D(0), min(taxable, upper) - lower) * D(rate))
        lower = upper
    ni = money(max(D(0), min(salary, D(50270)) - 12570) * D("0.08"))
    ni += money(max(D(0), salary - 50270) * D("0.02"))
    repayments = sum((money(max(D(0), salary - LOANS[plan][0]) * D(LOANS[plan][1]))
                      for plan in plans), D(0))
    return {"net": money(salary - tax - ni - repayments), "tax": tax, "ni": ni, "loans": repayments}


def verify():
    report = json.loads(Path(__file__).with_name("pay-rise-2026-27-v1.json").read_text(encoding="utf-8"))
    assert report["version"] == "1.0" and report["taxYear"] == "2026-27"
    plans = {item["id"]: item["plans"] for item in report["loanScenarios"]}
    assert len(report["rows"]) == 240
    for row in report["rows"]:
        before = annual(row["salaryBefore"], row["region"], plans[row["loanScenario"]])
        after = annual(row["salaryAfter"], row["region"], plans[row["loanScenario"]])
        extra = after["net"] - before["net"]
        results = {
            "netBefore": before["net"], "netAfter": after["net"],
            "extraIncomeTax": after["tax"] - before["tax"],
            "extraNI": after["ni"] - before["ni"],
            "extraLoanRepayments": after["loans"] - before["loans"],
            "extraNetAnnual": extra, "extraNetMonthlyEquivalent": money(extra / 12),
            "retainedPercent": money(extra / 1000 * 100),
        }
        for field, result in results.items():
            assert money(str(row[field])) == result, (row["region"], row["salaryBefore"], row["loanScenario"], field)
    print("Reproduced all 240 scenarios, including before/after net pay and each deduction difference.")


if __name__ == "__main__":
    verify()
