#!/usr/bin/env python3
"""Extract department narrative sections and the capital summary tables from
Bellingham's 2026 budget book (Department Budgets chapter, printed pp. 99-174).

Outputs:
  bellingham/data/department_narratives.jsonl  one record per department
  bellingham/data/capital_summary.csv          capital by department / by fund
"""
import csv
import json
import re
import sys
from pathlib import Path

import pdfplumber

sys.path.insert(0, str(Path(__file__).resolve().parent))
from parse_bellingham_budget_positions import rebuild_lines  # noqa: E402
from parse_bellingham_funds import value_tokens, MONEY  # noqa: E402

ROOT = Path(__file__).resolve().parent.parent
PDF = ROOT / "bellingham/raw/budget/2026-Adopted-Budget.pdf"
DATA = ROOT / "bellingham/data"

# printed page ranges (PDF page = printed + 2)
DEPARTMENTS = [
    ("Police Department", 100, 106, "Public Safety"),
    ("Fire Department", 107, 111, "Public Safety"),
    ("Municipal Court", 112, 113, "Public Safety"),
    ("Parks and Recreation Department", 114, 119, "Recreation and Culture"),
    ("Library", 120, 123, "Recreation and Culture"),
    ("Museum", 124, 125, "Recreation and Culture"),
    ("Planning & Community Development Department", 126, 131,
     "Planning and Community Development"),
    ("Hearing Examiner", 132, 132, "Planning and Community Development"),
    ("Human Resources Department", 133, 136, "General Government"),
    ("Information Technology Services Department", 137, 140,
     "General Government"),
    ("Finance Department", 141, 143, "General Government"),
    ("Legal Department", 144, 146, "General Government"),
    ("Executive Department", 147, 149, "General Government"),
    ("Legislative Department", 150, 150, "General Government"),
    ("Non-Departmental", 151, 151, "General Government"),
    ("Public Facilities District", 152, 152, "Discrete Component Unit"),
    ("Public Works", 153, 164, "Public Works"),
]

FOOTER = re.compile(
    r"^(City of Bellingham|2026 Adopted Budget|Page \d+|Department Budgets)")


def page_text(page):
    out = []
    for _, clusters in rebuild_lines(page):
        line = " ".join(t for _, t in clusters).strip()
        if line and not FOOTER.match(line):
            out.append(line)
    return "\n".join(out)


def extract_narratives(pdf):
    recs = []
    for name, first, last, group in DEPARTMENTS:
        text = "\n".join(page_text(pdf.pages[p + 1]) for p in range(first, last + 1))
        recs.append({
            "department": name, "functional_group": group,
            "printed_pages": f"{first}-{last}", "text": text,
        })
    return recs


def extract_capital(pdf):
    """Capital Summary by Department / by Fund tables (printed p.167)."""
    rows = []
    mode = None
    for p in (168, 169, 170):  # PDF pages around printed 166-168
        for _, clusters in rebuild_lines(pdf.pages[p]):
            line = " ".join(t for _, t in clusters).strip()
            if "Capital Summary by Department" in line:
                mode = "department"
                continue
            if "Capital Summary by Fund" in line:
                mode = "fund"
                continue
            if mode is None or FOOTER.match(line):
                continue
            # Values render with intra-number spaces ('2 ,428,000'); find the
            # first money-like token, strip spaces in the region, re-tokenize.
            m = re.search(r"[\d(][\d ()]*,\s*\d", line)
            if not m:
                continue
            label = line[: m.start()].strip(" .-–|")
            if not label or label in ("Adopted", "Fund"):
                continue
            region = line[m.start():].replace(" ", "")
            vals = value_tokens(region)
            if len(vals) >= 2:
                rows.append({"table": mode, "label": label,
                             "fy2026": vals[0],
                             "total_2027_2031": sum(vals[1:7]),
                             "values": ";".join(str(v) for v in vals)})
    return rows


def main():
    with pdfplumber.open(PDF) as pdf:
        recs = extract_narratives(pdf)
        cap = extract_capital(pdf)
    with open(DATA / "department_narratives.jsonl", "w") as f:
        for r in recs:
            f.write(json.dumps(r) + "\n")
    if cap:
        with open(DATA / "capital_summary.csv", "w", newline="") as f:
            w = csv.DictWriter(f, fieldnames=list(cap[0].keys()))
            w.writeheader()
            w.writerows(cap)
    print(f"departments: {len(recs)}, capital rows: {len(cap)}")
    for r in recs:
        print(f"  {r['department'][:44]:44} {len(r['text']):6} chars")
    for c in cap[:12]:
        print(" ", c["table"], "|", c["label"][:40], "|", c["fy2026"])


if __name__ == "__main__":
    main()
