#!/usr/bin/env python3
"""Assemble the Bellingham entity graph: governments and quasi-entities the
city is connected to, with dollar-weighted edges where documented.

Node/edge skeleton is curated from the 2021 ACFR notes (reporting entity,
note 15 interlocal agreements), the 2026 budget book, and the Aug 2026
recon (candidate-cities-recon.md). Dollar weights are computed from
fund_lines.csv (2026 adopted) where possible, otherwise cited from the ACFR
(2021 actuals) and flagged as such.

Output: bellingham/data/entity_graph.json
"""
import csv
import json
from collections import defaultdict
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
DATA = ROOT / "bellingham/data"


def fund_metric(lines, code, item, section=None):
    return sum(int(r["fy2026"]) for r in lines
               if r["fund_code"] == code and r["line_item"] == item
               and (section is None or r["section"] == section))


def main():
    lines = list(csv.DictReader(open(DATA / "fund_lines.csv")))

    nodes = [
        {"id": "bellingham", "name": "City of Bellingham", "type": "city",
         "note": "First-class charter city, mayor-council. 1,120.4 budgeted FTE (2026); $544.3M all-funds budget."},
        {"id": "whatcom-county", "name": "Whatcom County", "type": "county",
         "note": "Overlapping general government: superior court, jail, health dept, elections, assessor; EMS sales tax collector."},
        {"id": "bsd501", "name": "Bellingham School District 501", "type": "school-district",
         "note": "Independent taxing district, ~12,000 students; 4th-largest employer in county. Separate payroll entity."},
        {"id": "port", "name": "Port of Bellingham", "type": "port-district",
         "note": "Independent port district: airport, marinas, waterfront redevelopment."},
        {"id": "wta", "name": "Whatcom Transportation Authority", "type": "transit-authority",
         "note": "Countywide transit PTBA; Bellingham is primary service area. City has no transit FTEs."},
        {"id": "pud1", "name": "PUD No. 1 of Whatcom County", "type": "pud",
         "note": "Minor player: industrial water. Electricity in city is Puget Sound Energy (investor-owned)."},
        {"id": "fd8", "name": "Whatcom County Fire District 8", "type": "fire-district",
         "note": "Distinct municipal entity; city provides fire/EMS service under ILA 2016-0336. RFA consolidation planned (ballot target 2027)."},
        {"id": "pfd", "name": "Bellingham-Whatcom Public Facilities District", "type": "component-unit",
         "note": "City's one discrete component unit (RCW 35.57, est. 2002); budgeted as fund 965."},
        {"id": "lwwsd", "name": "Lake Whatcom Water & Sewer District", "type": "water-district",
         "note": "Partner in Lake Whatcom Management Program (drinking-water watershed)."},
        {"id": "dispatch-members", "name": "What-Comm / Prospect member agencies", "type": "member-pool",
         "note": "County + cities + fire districts paying into the two dispatch centers the city operates (police: What-Comm; fire/EMS: Prospect)."},
        {"id": "state-wa", "name": "State of Washington", "type": "state",
         "note": "Gas tax, shared revenues, grants (Ecology, TIB, Commerce); Dept of Ecology co-funds remediation."},
        {"id": "federal", "name": "Federal government", "type": "federal",
         "note": "HUD CDBG/HOME entitlements, transportation grants, equitable-share forfeitures."},
        {"id": "wcog", "name": "Whatcom Council of Governments", "type": "regional-council",
         "note": "MPO/regional transportation planning; city is member jurisdiction."},
        {"id": "wcls", "name": "Whatcom County Library System", "type": "library-district",
         "note": "County library district surrounding the CITY-run Bellingham Public Library (a city department) — reciprocal borrowing."},
    ]

    disp_charges = fund_metric(lines, "160", "CHARGES FOR GOODS AND SRVS.")
    disp_ig = fund_metric(lines, "160", "INTERGOVERNMENTAL REVENUE")
    medic_charges = fund_metric(lines, "470", "CHARGES FOR GOODS AND SRVS.")
    street_ig = fund_metric(lines, "111", "INTERGOVERNMENTAL REVENUE")
    rem_ig = fund_metric(lines, "136", "INTERGOVERNMENTAL REVENUE")
    hud_ig = fund_metric(lines, "190", "INTERGOVERNMENTAL REVENUE")
    gf_ig = fund_metric(lines, "001", "INTERGOVERNMENTAL REVENUE")
    storm_ig = fund_metric(lines, "430", "INTERGOVERNMENTAL REVENUE")
    pfd_exp = fund_metric(lines, "965", "TOTAL EXPENDITURE")

    edges = [
        {"from": "whatcom-county", "to": "bellingham", "type": "service-contract",
         "service": "Medic One ambulance service (city provides county-wide EMS transport)",
         "dollars_2026": medic_charges, "direction": "money-in",
         "source": "ACFR note 15; fund 470 charges for services"},
        {"from": "dispatch-members", "to": "bellingham", "type": "member-contributions",
         "service": "911 dispatch: What-Comm (police) + Prospect (fire/EMS), operated by city staff",
         "dollars_2026": disp_charges + disp_ig, "direction": "money-in",
         "source": "ACFR note 15; fund 160 (charges + intergovernmental)"},
        {"from": "fd8", "to": "bellingham", "type": "service-contract",
         "service": "Fire and EMS service to District 8 under ILA 2016-0336",
         "dollars_2021": 1242019, "direction": "money-in",
         "source": "ACFR note 15 (2021 actual; RFA consolidation contemplated)"},
        {"from": "bellingham", "to": "pfd", "type": "component-unit",
         "service": "Discretely presented component unit; city budget includes PFD fund 965",
         "dollars_2026": pfd_exp, "direction": "money-out",
         "source": "ACFR reporting-entity note; fund 965"},
        {"from": "bellingham", "to": "port", "type": "joint-plan",
         "service": "Waterfront District redevelopment: sub-area plan, development agreement, facilities ILA (2013)",
         "direction": "joint", "source": "ACFR note 15"},
        {"from": "bellingham", "to": "whatcom-county", "type": "joint-program",
         "service": "Lake Whatcom Management Program w/ county + LWWSD ($60.1M 2020-24 workplan); AIS prevention",
         "direction": "joint", "source": "ACFR note 15"},
        {"from": "lwwsd", "to": "bellingham", "type": "joint-program",
         "service": "Lake Whatcom Management Program / AIS cost sharing",
         "direction": "joint", "source": "ACFR note 15"},
        {"from": "state-wa", "to": "bellingham", "type": "grants-shared-revenue",
         "service": "Street/transportation grants + remediation (Ecology) + shared revenues",
         "dollars_2026": street_ig + rem_ig + storm_ig, "direction": "money-in",
         "source": "funds 111/136/430 intergovernmental (state+federal mixed)"},
        {"from": "federal", "to": "bellingham", "type": "entitlement-grants",
         "service": "HUD CDBG/HOME entitlements",
         "dollars_2026": hud_ig, "direction": "money-in",
         "source": "fund 190 intergovernmental"},
        {"from": "whatcom-county", "to": "bellingham", "type": "shared-revenue",
         "service": "General Fund intergovernmental (county/state shared, liquor, criminal justice)",
         "dollars_2026": gf_ig, "direction": "money-in",
         "source": "fund 001 intergovernmental (mixed sources)"},
        {"from": "bellingham", "to": "wcog", "type": "membership",
         "service": "Regional transportation planning (MPO)", "direction": "joint",
         "source": "recon"},
        {"from": "bsd501", "to": "bellingham", "type": "overlapping-jurisdiction",
         "service": "Same geography, independent budget/payroll; SRO and facility-use agreements typical",
         "direction": "none", "source": "recon"},
        {"from": "wta", "to": "bellingham", "type": "overlapping-jurisdiction",
         "service": "Transit service inside city; no city transit workforce",
         "direction": "none", "source": "recon"},
        {"from": "pud1", "to": "bellingham", "type": "overlapping-jurisdiction",
         "service": "Industrial water supply", "direction": "none", "source": "recon"},
        {"from": "wcls", "to": "bellingham", "type": "reciprocal-service",
         "service": "Reciprocal borrowing with city-run library", "direction": "none",
         "source": "recon"},
    ]

    graph = {"as_of": "2026 adopted budget + 2021 ACFR notes",
             "nodes": nodes, "edges": edges}
    with open(DATA / "entity_graph.json", "w") as f:
        json.dump(graph, f, indent=1)
    print(f"nodes: {len(nodes)}, edges: {len(edges)}")
    for e in edges:
        d = e.get("dollars_2026") or e.get("dollars_2021") or 0
        print(f"  {e['from']:18} -> {e['to']:18} {e['type']:26} "
              f"{('$'+format(d, ',')) if d else '—':>12}")


if __name__ == "__main__":
    main()
