#!/usr/bin/env python3
"""Generate cumulative contributor + claims PNG for Twitter embedding."""

import json
import subprocess
import sys
from datetime import datetime, timedelta
from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import MaxNLocator

ACCENT = "#00d4aa"
PURPLE = "#7c3aed"
BG = "#0a0a0a"
TEXT = "#e0e0e0"
SUBTLE = "#555555"
OUTPUT = Path("/opt/teleo-eval/static/contributor-graph.png")


def get_data():
    """Fetch from local API."""
    import urllib.request
    with urllib.request.urlopen("http://localhost:8081/api/contributor-growth") as r:
        return json.loads(r.read())


def build_continuous_series(milestones, start_date, end_date):
    """Expand milestone-only contributor data into daily series."""
    dates = []
    values = []
    current = 0
    milestone_map = {}
    for m in milestones:
        d = datetime.strptime(m["date"], "%Y-%m-%d").date()
        milestone_map[d] = m["cumulative"]

    d = start_date
    while d <= end_date:
        if d in milestone_map:
            current = milestone_map[d]
        dates.append(d)
        values.append(current)
        d += timedelta(days=1)
    return dates, values


def render(data, output_path):
    fig, ax1 = plt.subplots(figsize=(12, 6.3), dpi=100)
    fig.patch.set_facecolor(BG)
    ax1.set_facecolor(BG)

    claims = data["cumulative_claims"]
    contribs = data["cumulative_contributors"]

    claim_dates = [datetime.strptime(c["date"], "%Y-%m-%d").date() for c in claims]
    claim_values = [c["cumulative"] for c in claims]

    start = min(claim_dates)
    end = max(claim_dates)

    contrib_dates, contrib_values = build_continuous_series(contribs, start, end)

    # Claims line (left y-axis)
    ax1.fill_between(claim_dates, claim_values, alpha=0.15, color=ACCENT)
    ax1.plot(claim_dates, claim_values, color=ACCENT, linewidth=2.5, label="Claims")
    ax1.set_ylabel("Claims", color=ACCENT, fontsize=12, fontweight="bold")
    ax1.tick_params(axis="y", colors=ACCENT, labelsize=10)
    ax1.set_ylim(bottom=0)

    # Contributors line (right y-axis)
    ax2 = ax1.twinx()
    ax2.set_facecolor("none")
    ax2.fill_between(contrib_dates, contrib_values, alpha=0.1, color=PURPLE, step="post")
    ax2.step(contrib_dates, contrib_values, color=PURPLE, linewidth=2.5,
             where="post", label="Contributors")
    ax2.set_ylabel("Contributors", color=PURPLE, fontsize=12, fontweight="bold")
    ax2.tick_params(axis="y", colors=PURPLE, labelsize=10)
    ax2.yaxis.set_major_locator(MaxNLocator(integer=True))
    ax2.set_ylim(bottom=0, top=max(contrib_values) * 1.8)

    # Annotate contributor milestones with staggered offsets to avoid overlap
    offsets = {}
    for i, m in enumerate(contribs):
        d = datetime.strptime(m["date"], "%Y-%m-%d").date()
        val = m["cumulative"]
        names = [n["name"] for n in m["new"]]
        if len(names) <= 2:
            label = ", ".join(names)
        else:
            label = f"+{len(names)}"
        y_off = 8 + (i % 2) * 14
        ax2.annotate(label, (d, val),
                     textcoords="offset points", xytext=(5, y_off),
                     fontsize=7, color=PURPLE, alpha=0.8)

    # Hero stats
    total_claims = data["summary"]["total_claims"]
    total_contribs = data["summary"]["total_contributors"]
    days = data["summary"]["days_active"]
    fig.text(0.14, 0.88, f"{total_claims:,} claims", fontsize=22,
             color=ACCENT, fontweight="bold", ha="left")
    fig.text(0.14, 0.82, f"{total_contribs} contributors · {days} days",
             fontsize=13, color=TEXT, ha="left", alpha=0.7)

    # X-axis
    ax1.xaxis.set_major_formatter(mdates.DateFormatter("%b %d"))
    ax1.xaxis.set_major_locator(mdates.WeekdayLocator(interval=2))
    ax1.tick_params(axis="x", colors=SUBTLE, labelsize=9, rotation=0)

    # Remove spines
    for ax in [ax1, ax2]:
        for spine in ax.spines.values():
            spine.set_visible(False)

    # Subtle grid on claims axis only
    ax1.grid(axis="y", color=SUBTLE, alpha=0.2, linewidth=0.5)
    ax1.set_axisbelow(True)

    # Branding
    fig.text(0.98, 0.02, "livingip.xyz", fontsize=9, color=SUBTLE,
             ha="right", style="italic")

    plt.tight_layout(rect=[0, 0.03, 1, 0.78])
    output_path.parent.mkdir(parents=True, exist_ok=True)
    fig.savefig(output_path, facecolor=BG, bbox_inches="tight", pad_inches=0.3)
    plt.close(fig)
    print(f"Saved to {output_path} ({output_path.stat().st_size:,} bytes)")


if __name__ == "__main__":
    out = Path(sys.argv[1]) if len(sys.argv) > 1 else OUTPUT
    data = get_data()
    render(data, out)
