#!/usr/bin/env python3
"""
Pod Capacity & Bandwidth Forecast — v3 (dev-status-bot aligned)

Drops our v1/v2 Jira pull entirely. Uses the canonical trend data file from
RocketRez/dev-status-bot (also rendered live at rocketrez-labs.com/dev-metrics):

  Canonical source: https://github.com/RocketRez/dev-status-bot/blob/main/reports/trend-data.json
  Live render:      https://rocketrez-labs.com/dev-metrics/trend-data.json

Methodology
-----------
- Capacity unit: Jira issues_completed per Saturday-Friday week, per dev-status-bot.
- Bootstrap 5,000 samples × 13 weeks → Q3 capacity distribution per pod.
- Demand: Q3 roadmap items sized in T-shirts × Q3-effort-share, plus KTLO baseline
  (avg bugs_resolved per week × 13).
- Pod team mapping (from team_id field in trend-data.json):
    origin    = ['origin-team', 'ro']
    orion     = ['orion-team']
    reporting = ['reporting', 'reporting-team']

Inputs
------
data/dev-metrics/trend-data.json — snapshot from the dev-status-bot repo.

Refresh options (the dev-status-bot repo is private, so plain curl won't work):

  # Option A: GitHub CLI (recommended; handles auth)
  gh api repos/RocketRez/dev-status-bot/contents/reports/trend-data.json \
    --jq '.content' | base64 -d > data/dev-metrics/trend-data.json

  # Option B: download via the live render (if your network reaches it)
  curl -L -o data/dev-metrics/trend-data.json \
    https://rocketrez-labs.com/dev-metrics/trend-data.json

  # Option C: open the GitHub URL in your browser, save as
  https://github.com/RocketRez/dev-status-bot/blob/main/reports/trend-data.json

Output
------
data/capacity/forecast.json
"""

import json
import random
import statistics
from pathlib import Path
from datetime import datetime, timezone

random.seed(42)

ROOT = Path(__file__).resolve().parent.parent.parent
TREND = ROOT / "data" / "dev-metrics" / "trend-data.json"
OUT   = ROOT / "data" / "capacity" / "forecast.json"

if not TREND.exists():
    raise SystemExit(
        f"Missing {TREND}. Refresh with:\n"
        f"  gh api repos/RocketRez/dev-status-bot/contents/reports/trend-data.json \\\n"
        f"    --jq '.content' | base64 -d > {TREND.relative_to(ROOT)}\n"
        f"  (or: curl https://rocketrez-labs.com/dev-metrics/trend-data.json > {TREND.relative_to(ROOT)})"
    )

with open(TREND) as f:
    trend = json.load(f)

# --- Constants ---
N_BOOTSTRAP = 5000
Q3_WEEKS = 13
PERCENTILES = [5, 25, 50, 75, 95]

POD_TEAM_MAP = {
    "origin":    ["origin-team", "ro"],
    "orion":     ["orion-team"],
    "reporting": ["reporting", "reporting-team"],
}

# T-shirt → issue counts (calibrated to Jira-issue-equivalents, same as v1)
TSHIRT_ISSUES = {"XS": 1, "S": 3, "M": 10, "L": 25, "XL": 60}

# --- Q3 roadmap (T-shirt sized × Q3-effort-share) ---
ROADMAP_Q3 = {
    "origin": [
        {"title": "PCI DSS 6.4.3 CSP P1 (tail)",       "size": "L",  "q3_share": 0.4, "ticket": "RX-7976"},
        {"title": "Toast Phase 1 (completion)",        "size": "L",  "q3_share": 0.5, "ticket": "RX-7403"},
        {"title": "Family Memberships (continuing)",   "size": "XL", "q3_share": 0.3, "ticket": "RX-6803"},
        {"title": "Gifting / Deferred Activation",     "size": "L",  "q3_share": 0.6, "ticket": "RX-7059"},
        {"title": "Insights V2 follow-on",             "size": "M",  "q3_share": 0.5, "ticket": "RX-8005"},
        {"title": "Release cadence (3.85-3.87)",       "size": "M",  "q3_share": 1.0, "ticket": None},
    ],
    "orion": [
        {"title": "Operate Mariner's + waterparks",    "size": "L",  "q3_share": 1.0, "ticket": None},
        {"title": "Membership Activation (completion)","size": "L",  "q3_share": 0.5, "ticket": "ORI-1702"},
        {"title": "Gift Card + Refund Waterfall",      "size": "M",  "q3_share": 0.6, "ticket": "ORI-1500"},
        {"title": "AM/PM pass support",                "size": "M",  "q3_share": 0.8, "ticket": "ORI-1514"},
        {"title": "Membership photo capture",          "size": "M",  "q3_share": 0.6, "ticket": "ORI-1781"},
        {"title": "Admin terminal management UI",      "size": "M",  "q3_share": 0.7, "ticket": "ORI-1095"},
        {"title": "E2E test automation expansion",     "size": "M",  "q3_share": 0.7, "ticket": None},
    ],
    "reporting": [
        {"title": "RM3 Power BI (completion)",         "size": "L",  "q3_share": 0.5, "ticket": "RX-6890"},
        {"title": "RM4 Telerik migration (kickoff)",   "size": "XL", "q3_share": 0.25,"ticket": "RX-6891"},
        {"title": "Stripe Payments ODS",               "size": "M",  "q3_share": 0.7, "ticket": "RX-7337"},
        {"title": "Mission Control expansion",         "size": "L",  "q3_share": 0.4, "ticket": "RX-6319"},
        {"title": "Customer report mods (steady)",     "size": "M",  "q3_share": 1.0, "ticket": None},
    ],
}

# --- Helpers ---
def pct(sorted_vals, p):
    if not sorted_vals: return 0
    k = (len(sorted_vals) - 1) * p / 100
    f = int(k); c = min(f + 1, len(sorted_vals) - 1)
    return round(sorted_vals[f] + (sorted_vals[c] - sorted_vals[f]) * (k - f), 1)

def bootstrap_q3(weekly_series, n=N_BOOTSTRAP):
    samples = [sum(random.choice(weekly_series) for _ in range(Q3_WEEKS)) for _ in range(n)]
    return sorted(samples)

def pod_weekly_issues(pod):
    """Return [(week_end, issues_completed), ...] aggregated across this pod's team_ids."""
    ids = set(POD_TEAM_MAP[pod])
    by_week = {}
    for row in trend.get("issues", []):
        if row.get("team_id") in ids:
            w = row.get("week_end")
            by_week[w] = by_week.get(w, 0) + (row.get("completed") or 0)
    weeks = sorted(by_week.keys())
    return [(w, by_week[w]) for w in weeks]

def pod_weekly_bug_resolved(pod):
    """Return weekly bugs_resolved series for this pod."""
    ids = set(POD_TEAM_MAP[pod])
    by_week = {}
    for row in trend.get("bugs", []):
        if row.get("team_id") in ids:
            w = row.get("week_end")
            # bugs schema may vary: try both 'bugs_resolved' and 'resolved' keys
            count = row.get("bugs_resolved", row.get("resolved", 0)) or 0
            by_week[w] = by_week.get(w, 0) + count
    return [by_week[w] for w in sorted(by_week.keys())]

# --- Main loop ---
PODS = ["origin", "orion", "reporting"]

result = {
    "_meta": {
        "version": "v3",
        "model": "Monte Carlo bootstrap over per-week issues_completed from rocketrez-labs.com/dev-metrics",
        "samples": N_BOOTSTRAP,
        "q3Weeks": Q3_WEEKS,
        "weekAlignment": "Saturday-Friday",
        "source": "https://rocketrez-labs.com/dev-metrics/trend-data.json (RocketRez/dev-status-bot)",
        "generatedAt": datetime.now(timezone.utc).isoformat(),
        "tshirtIssues": TSHIRT_ISSUES,
        "podTeamMap": POD_TEAM_MAP,
        "forecastQuarter": "2026 Q3 (Jul-Sep), 13 weeks",
        "assumptions": [
            "Capacity unit = Jira issues_completed per Saturday-Friday week (per dev-status-bot)",
            "Per-pod weekly throughput sampled with replacement over 42 historical weeks",
            "Q3 forecast = sum of 13 weekly samples, repeated 5,000 times",
            "T-shirt → issue counts (XS=1, S=3, M=10, L=25, XL=60)",
            "KTLO baseline = avg bugs_resolved per week × 13 (proxy for ongoing fix load)",
        ]
    },
    "pods": {}
}

for pod in PODS:
    weeks_issues = pod_weekly_issues(pod)
    if not weeks_issues:
        print(f"WARN: no weekly data for {pod}")
        continue
    weeks = [w for w, _ in weeks_issues]
    series = [n for _, n in weeks_issues]

    # Bootstrap Q3 capacity
    q3_cap = bootstrap_q3(series)
    q3_cap_pcts = {f"P{p}": pct(q3_cap, p) for p in PERCENTILES}

    # KTLO from bug-resolved series
    bug_series = pod_weekly_bug_resolved(pod)
    ktlo_mean = (sum(bug_series) / len(bug_series)) if bug_series else 0
    ktlo_q3_p50 = round(ktlo_mean * Q3_WEEKS, 1)

    # Roadmap demand
    items = ROADMAP_Q3[pod]
    roadmap_total = 0.0
    detail = []
    for it in items:
        issues = TSHIRT_ISSUES[it["size"]] * it["q3_share"]
        roadmap_total += issues
        detail.append({**it, "issues_q3": round(issues, 1)})

    total_demand = round(roadmap_total + ktlo_q3_p50, 1)
    bw = {f"P{p}": round(pct(q3_cap, p) - total_demand, 1) for p in PERCENTILES}
    p_meet = sum(1 for s in q3_cap if s >= total_demand) / len(q3_cap)
    headroom_pct = round(bw["P50"] / q3_cap_pcts["P50"] * 100) if q3_cap_pcts["P50"] else 0
    verdict = (
        "Substantial bandwidth available" if p_meet >= 0.85 else
        "Meets commit, modest room"        if p_meet >= 0.70 else
        "Tight — coin flip territory"      if p_meet >= 0.45 else
        "Likely overcommitted"
    )

    series_stats = {
        "n":      len(series),
        "min":    min(series),
        "max":    max(series),
        "mean":   round(statistics.mean(series), 1),
        "median": int(statistics.median(series)),
        "stdev":  round(statistics.stdev(series), 1) if len(series) > 1 else 0.0,
    }

    result["pods"][pod] = {
        "teamIds": POD_TEAM_MAP[pod],
        "weeklyHistory": [
            {"week_end": w, "issues_completed": n} for w, n in weeks_issues
        ],
        "monthlyStats": series_stats,
        "q3CapacityForecast": q3_cap_pcts,
        "q3KtloForecastP50":  ktlo_q3_p50,
        "roadmapDemand": {
            "totalIssues": round(roadmap_total, 1),
            "items":       detail,
        },
        "totalDemand":              total_demand,
        "bandwidthAtPercentile":    bw,
        "probabilityMeetsCommit":   round(p_meet, 3),
        "headroomPctP50":           headroom_pct,
        "verdict":                  verdict,
    }

OUT.parent.mkdir(parents=True, exist_ok=True)
with open(OUT, "w") as f:
    json.dump(result, f, indent=2)

print(f"Wrote {OUT}")
print()
print(f"{'Pod':<12} {'Weeks':>6} {'Avg/wk':>8} {'P50':>7} {'Demand':>8} {'BW@P50':>8} {'P(meet)':>8} {'Headroom':>10} {'Verdict':>34}")
print("-" * 110)
for pod in PODS:
    p = result["pods"][pod]
    s = p["monthlyStats"]
    print(
        f"{pod:<12} {s['n']:>6} {s['mean']:>8} "
        f"{p['q3CapacityForecast']['P50']:>7} {p['totalDemand']:>8} "
        f"{p['bandwidthAtPercentile']['P50']:>8} {p['probabilityMeetsCommit']:>8.1%} "
        f"{p['headroomPctP50']:>9}% {p['verdict']:>34}"
    )
