"""Tests from Lab 07: the prompt-part sizes of the made-up Ledgerly assistant, and the real payouts
tool output for 2026-03-06 (400 rows). Run: pytest test_context_practice.py"""
from context_practice import fit_by_priority, keep_the_end, offload, profile, query

# The lab's measured token counts per part, rebuilt as words (tokens() counts words here)
SIZES = {"rules": 72, "tools": 2361, "memory": 41, "documents": 224, "history": 624, "question": 10}
PARTS = {name: " ".join(["w"] * n) for name, n in SIZES.items()}  # in prompt order

# 2026-03-06: one letter for the status (p paid, f failed, q pending), then amount_usd
PACKED = (
    "p934.33,p3981.01,p3201.49,p1854.36,p653.81,p1247.95,p2289.09,p3354.25,p2818.52,p2003.44,p1226.62,"
    "p2323.14,p3470.57,p203.37,p660.61,p507.36,p2476.23,p3322.27,p846.99,p1502.1,p2772.75,p2846.68,p3084.89,"
    "p2416.74,p925.59,p3184.38,p2252.23,p1936.79,p462.56,p1487.64,p2939.18,p2856.17,p3832.02,p3747.24,"
    "p2455.19,p3798.72,p1202.59,p3140.91,p3138.03,p562.81,p2031.54,p3296.47,f395.02,p3487.63,p1938.03,"
    "p308.91,p1878.08,p1268.99,p52.38,p333.79,p3875.35,p46.28,p3338.24,p1695.21,p2428.75,p1586.52,p2523.44,"
    "p3724.7,p1964.68,p112.91,p3638.47,p3735.33,p3697.82,p621.45,p1791.04,p3483.19,p635.05,p2419.95,p3949.95,"
    "p922.45,p3414.07,p1247.64,p820.98,p1121.17,p97.1,p3073.87,p3664.41,p3341.73,p1311.31,p988.65,p757.59,"
    "p3897.34,p3419.48,p1308.84,p2760.07,p1732.73,p3440.3,p916.84,p1735.57,p1454.13,f651.5,p2600.73,p1016.29,"
    "p1775.36,p2823.34,p1983.66,p3417.68,p2731.79,p2621.1,p2680.81,f856.71,p2804.63,p2745.86,p2585.85,"
    "p2286.21,p39.81,p58.89,f1729.3,p3484.98,p2762.97,p1897.66,p1063.04,p1465.32,p1575.72,p2793.96,p1526.01,"
    "p197.58,p3079.07,p2534.63,p704.5,p1646.12,p2342.63,p3659.21,p633.2,p2140.06,p2356.83,p3742.52,p3602.2,"
    "f1580.93,p3366.59,p1523.37,p3866.59,p421.88,p3617.01,p2841.42,p77.68,p524.33,p1687.51,p2369.56,p94.23,"
    "p3928.1,p179.28,p2657.97,p606.64,p1410.11,p1498.02,p1461.53,p266.24,p2170.35,p254.04,p2167.23,p3067.09,"
    "p2945.08,p85.68,p1737.28,p2733.5,p466.77,p1869.72,f695.58,p2437.08,p2927.02,p1087.21,p3908.37,p2122.99,"
    "p1700.16,p615.48,p2202.25,p970.45,p824.86,p1803.11,p3756.61,p234.17,p1281.3,p2489.49,p60.83,f1641.13,"
    "p3406.03,p1615.45,p3807.58,p425.93,p1436.71,p2013.88,p2262.37,p166.93,p2434.67,f2602.0,p3270.87,"
    "p3216.73,p213.59,p2887.28,p1942.81,p3234.46,p3369.93,p1011.45,p964.84,p1163.52,p231.68,p961.3,p594.73,"
    "p3672.49,p740.19,p3591.03,f3997.46,p320.05,p3460.66,p3468.68,p659.76,p2931.85,f3852.77,p1959.69,"
    "p2527.25,p1091.03,p3873.02,p2906.04,p1156.13,p3234.6,p2279.61,p1807.61,p1390.66,p1314.47,p3151.34,"
    "p1740.51,f3228.17,p791.21,p3449.26,p1454.35,f3948.62,p420.33,p2580.2,p214.3,p3407.66,p2535.06,p2140.11,"
    "p3840.6,p3026.54,p3122.57,p3163.49,p2875.57,p2619.81,f2524.7,p517.74,p1697.38,p3239.15,p74.34,p276.22,"
    "p1737.53,p2686.94,p2282.7,p1869.59,p2528.01,p1043.0,p742.92,p3722.91,p1229.09,f2301.6,p1973.01,p1863.89,"
    "p3676.53,p2981.57,p2177.56,p3574.25,p2935.23,p1463.5,p1290.2,p1668.77,f1758.0,p3301.31,p317.33,p1056.58,"
    "p3327.75,p1003.06,p1252.4,p2722.83,p2677.04,p3256.32,p1041.34,p1480.53,p3510.71,p3587.61,p680.62,"
    "p1319.11,p884.91,p3381.3,p1978.07,p1288.14,p3573.24,p2823.71,p3048.97,p605.11,p3760.26,p400.23,p3335.83,"
    "p3979.56,p2898.59,p1312.35,f1959.39,p3145.27,p2192.0,p3601.42,p1105.84,p631.41,p1039.2,p1340.09,p175.87,"
    "p2315.74,p3432.85,p1418.02,f1126.41,f1578.07,p1485.25,p2434.65,p3077.07,p526.9,p497.72,p1984.25,p94.19,"
    "p1904.18,p1555.57,p695.69,p50.81,p3997.65,p1482.07,p105.21,p1685.93,p439.85,p1027.67,p2625.24,p3486.01,"
    "p1014.32,p3888.29,p3905.68,p2099.58,p3429.77,p322.44,p258.32,p472.91,p2708.71,p3334.69,p1889.5,p3951.2,"
    "p3318.59,p2677.7,p2828.47,p1285.94,p2021.27,p618.68,p2984.16,p720.47,p3621.98,p3638.36,p2890.05,"
    "p3372.63,p153.28,p1148.41,p86.58,p729.5,p937.43,p316.67,p2569.09,p1474.96,p1000.06,p2110.13,p2532.49,"
    "p2321.92,p1787.56,p2570.23,p1852.03,f290.9,p732.31,p1954.21,p2428.27,p1451.52,f3601.95,p1206.88,p2467.5,"
    "p3907.86,p3436.46,p2998.66,p3127.27,p1759.33,p3590.44,p2260.66,f592.95,p2010.54,p1153.56,p761.64,"
    "p2729.08,p3332.49,p3300.21,p2684.8,p2273.64,p1168.39,p827.11,p360.14,p503.65,p3445.91,p2169.77,p1893.92,"
    "p1169.72,p2891.24,"
)
STATUS = {"p": "paid", "f": "failed", "q": "pending"}
FIRST_TWO = [{"payout_id": "po_20260306_0000", "customer": "merchant_6759", "amount_usd": 934.33, "currency": "USD", "status": "paid", "bank": "harbor-cu", "created_at": "2026-03-06T09:16:00Z", "attempts": 1, "failure_code": None, "batch": "batch_4"}, {"payout_id": "po_20260306_0001", "customer": "merchant_5057", "amount_usd": 3981.01, "currency": "USD", "status": "paid", "bank": "first-river", "created_at": "2026-03-06T11:17:00Z", "attempts": 2, "failure_code": None, "batch": "batch_4"}]


def night_rows():
    rows = [{"status": STATUS[x[0]], "amount_usd": float(x[1:])} for x in PACKED.strip(",").split(",")]
    rows[0] = FIRST_TWO[0]
    rows[1] = FIRST_TWO[1]
    return rows


def test_measure_where_the_tokens_go():
    p = profile(PARTS)
    assert p[0] == ("tools", 2361, 70.9)
    assert p[-1] == ("question", 10, 0.3)
    assert [name for name, _, _ in p] == ["tools", "history", "documents", "rules", "memory", "question"]


def test_keeping_the_end_cuts_the_rules_first():
    assert keep_the_end(PARTS, 600) == ["history", "question"]
    assert keep_the_end(PARTS, 3332) == list(PARTS)
    assert "rules" not in keep_the_end(PARTS, 1200)


def test_cut_by_priority_at_600():
    docs = [" ".join(["d"] * 37)] * 6
    history = [" ".join(["m"] * 20)] * 30
    out = fit_by_priority(PARTS["rules"], PARTS["question"], PARTS["memory"], docs, history, PARTS["tools"], 600)
    assert out["kept"][:9] == ["rules", "question", "memory", "doc 1", "doc 2", "doc 3", "doc 4", "doc 5", "doc 6"]
    assert out["kept"][9:] == [f"msg {i}" for i in range(30, 18, -1)]   # the 12 newest messages
    assert out["dropped"] == ["18 oldest messages", "tools"]          # the lab dropped 18 too, and the tools
    assert out["tokens"] <= 600


def test_offload_returns_a_summary_not_the_rows():
    rows = night_rows()
    s = offload(rows, "payouts_2026-03-06.json")
    assert s["rows"] == 400 and s["saved_to"] == "payouts_2026-03-06.json"
    assert s["columns"][:5] == ["payout_id", "customer", "amount_usd", "currency", "status"]
    assert s["preview"] == FIRST_TWO
    assert len(str(s)) < len(str(rows)) / 20


def test_code_counts_and_adds_up():
    rows = night_rows()
    assert query(rows, "status", "failed", "amount_usd") == {"count": 21, "sum": 40913.16}
    # the model, reading the rows itself, said 10 ($26,980.62) from all 400 rows and 22 ($44,624.52) from the 21 failed ones
