"""Render OH HAI figures from adjacent aggregate activity.json.

Install matplotlib==3.10.8. Run: python reproduce-charts.py [activity.json]
Dates are UTC. Repository activity does not measure active agent execution.
"""
import json
import re
import sys
from datetime import datetime, timezone
from pathlib import Path

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

source = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).with_name('activity.json')
data = json.loads(source.read_text())
BG, INK, MUTED, GRID = '#111317', '#eeede7', '#b4b5af', '#34373b'
GREEN, BLUE, PURPLE = '#bada74', '#87bdf9', '#ba9df3'
plt.rcParams.update({'figure.facecolor': BG, 'axes.facecolor': BG, 'savefig.facecolor': BG,
    'text.color': INK, 'axes.labelcolor': MUTED, 'xtick.color': MUTED, 'ytick.color': MUTED,
    'axes.edgecolor': GRID, 'font.family': 'DejaVu Sans', 'font.size': 12,
    'svg.fonttype': 'path', 'svg.hashsalt': 'descant-ohhai-study-v1'})

def day(value):
    return datetime.fromisoformat(value[:10]).replace(tzinfo=timezone.utc)

def frame(title, ylabel):
    fig, ax = plt.subplots(figsize=(13, 5.6))
    fig.subplots_adjust(left=.08, right=.96, top=.82, bottom=.19)
    ax.set_title(title, loc='left', fontsize=21, weight='bold', pad=24)
    ax.spines[['top', 'right']].set_visible(False)
    ax.grid(axis='y', color=GRID, linewidth=.7)
    ax.set_ylabel(ylabel)
    ax.yaxis.set_major_locator(MaxNLocator(integer=True))
    locator = dates.AutoDateLocator(minticks=4, maxticks=7)
    ax.xaxis.set_major_locator(locator)
    ax.xaxis.set_major_formatter(dates.ConciseDateFormatter(locator))
    return fig, ax

def save(fig, name):
    target = source.parent / name
    fig.savefig(target, metadata={'Date': None})
    # Rendered glyphs carry the content; remove incidental font/XML comments.
    target.write_text(re.sub(r'<!--.*?-->', '', target.read_text(), flags=re.S))
    plt.close(fig)

def finish(fig, ax, name, footnote):
    ax.set_ylim(bottom=0)
    ax.legend(loc='upper left', frameon=False, labelcolor=INK, fontsize=11)
    ax.margins(x=.025)
    fig.text(.08, .045, footnote, fontsize=10, color=MUTED)
    save(fig, name)

def series(ax, rows, field, label, color):
    xs = [day(r['date']) for r in rows]
    ys = [r[field] for r in rows]
    ax.step(xs, ys, where='post', color=color, linewidth=3, label=f'{label} · {ys[-1]:,}')
    ax.scatter(xs[-1], ys[-1], color=color, s=55, zorder=5)

fig, ax = frame('Merged work over time', 'Cumulative pull requests')
for field, event, label, color in [('prsMergedCumulative','prsMerged','Merged',GREEN),
                                  ('prsCreatedCumulative','prsCreated','Opened',BLUE)]:
    rows = [r for r in data['daily'] if r[event]]
    series(ax, rows, field, label, color)
finish(fig, ax, 'work-progress.svg', 'UTC · Complete repository history · Each line stops at its last event')

fig, ax = frame('The changing backlog', 'Open issues')
rows = [r for r in data['daily'] if r['issuesCreated'] or r['issuesClosedEvents'] or r['issuesReopenedEvents']]
series(ax, rows, 'issuesOpen', 'Open at last issue event', BLUE)
finish(fig, ax, 'issue-progress.svg', 'UTC · End-of-day open issues · Every creation, close and reopen included')

fig, ax = plt.subplots(figsize=(13, 5.6))
fig.subplots_adjust(left=.27, right=.94, top=.82, bottom=.18)
ax.set_title('Where verification lives', loc='left', fontsize=21, weight='bold', pad=24)
rows = data['testInventory']
bars = ax.barh([r['surface'] for r in rows], [r['files'] for r in rows], color=GREEN, height=.62)
ax.invert_yaxis()
ax.spines[['top','right','left']].set_visible(False)
ax.tick_params(axis='y', length=0, labelsize=12)
ax.xaxis.set_major_locator(MaxNLocator(integer=True))
ax.set_xlabel('Test source files in the current tree')
ax.set_xlim(0, max(r['files'] for r in rows)*1.12)
ax.grid(axis='x', color=GRID, linewidth=.7)
ax.set_axisbelow(True)
ax.bar_label(bars, labels=[str(r['files']) for r in rows], padding=8, color=INK, fontsize=12)
fig.text(.08,.045,'525 named test/spec source files · File inventory, not test cases or a pass rate',fontsize=10,color=MUTED)
save(fig, 'test-inventory.svg')
print(json.dumps({'source':str(source),'figures':3,'testSourceFiles':sum(r['files'] for r in rows)}))
