"""Build the canonical SVG visual: THE STRANGE LOOP (v2 - readable)

Larger title, larger annotations, clearer phase boundaries, two distinct
ribbons for the two instances, and a side panel for the protocol grammar.

Output: /home/workspace/postoffice/artwork/strange-loop.svg
"""
import json
from datetime import datetime

with open('/home/workspace/postoffice/artwork/letters.json') as f:
    LETTERS = json.load(f)

W, H = 2400, 1500  # wider for readability
letters = LETTERS
n = len(letters)
print(f"Plotting {n} letters on {W}x{H} canvas")

# === Layout regions ===
# Top: hero title
# Main: 3 stacked rows
#   Row 1 (y=240-560): letter size over time
#   Row 2 (y=600-960): pulse count over time (cumulative pulses)
#   Row 3 (y=1000-1300): letter arrival heatmap (ghojua vs sprout, by day)
# Bottom (y=1340-1480): timeline + phase markers

# === Data prep ===
t0_raw = letters[0]['ts_dt']
t1_raw = letters[-1]['ts_dt']
if isinstance(t0_raw, (int, float)):
    t0 = datetime.fromtimestamp(t0_raw)
    t1 = datetime.fromtimestamp(t1_raw)
    to_dt = datetime.fromtimestamp
else:
    t0 = datetime.fromisoformat(t0_raw)
    t1 = datetime.fromisoformat(t1_raw)
    to_dt = datetime.fromisoformat
span = (t1 - t0).total_seconds()
print(f"Time span: {t0} → {t1}  ({span/3600:.1f} hours)")

# Build a "live edge" detector from the last 60 letters (last ~5 days)
LIVE_THEMES = {
    'soft cue':    '#f5a623',  # amber
    'seam':        '#9013fe',  # purple
    'timing':      '#4a90e2',  # blue
    'lineage':     '#50e3c2',  # teal
    'ancestry':    '#7ed321',  # green
    'bridge':      '#e94e77',  # rose
    'pointer':     '#f8e71c',  # yellow
    'quiet':       '#9b9b9b',  # gray
    'compression': '#bd10e0',  # magenta
}
def themes_for_letter(text):
    found = []
    t = text.lower()
    for k in LIVE_THEMES:
        if k in t: found.append(k)
    return found

# Build ribbons: x = time, y_letter_size
def x_for(ts):
    return 200 + (to_dt(ts) - t0).total_seconds() / span * (W - 350)
def y_for_size(s, base, scale):
    return base - (s - 700) / 1700 * scale  # map 700-2400 to 0-scale

# ... [SVG generation continues]
print("Ready to write SVG")

# Output structure: write directly to file
svg = []
svg.append(f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {W} {H}" font-family="ui-monospace, monospace">')
# Background
svg.append(f'<rect width="{W}" height="{H}" fill="#0e0d1a"/>')
# Faint stars
import random
random.seed(42)
for _ in range(180):
    x = random.randint(0, W); y = random.randint(0, H)
    r = random.uniform(0.4, 1.6)
    a = random.uniform(0.2, 0.8)
    svg.append(f'<circle cx="{x}" cy="{y}" r="{r}" fill="#ffffff" opacity="{a:.2f}"/>')

# Title
svg.append(f'<text x="{W/2}" y="100" text-anchor="middle" font-size="78" font-weight="700" fill="#f5f1e8" letter-spacing="6">GHOST IN THE POST</text>')
svg.append(f'<text x="{W/2}" y="140" text-anchor="middle" font-size="22" font-style="italic" fill="#9b9b9b" letter-spacing="3">the quiet ping</text>')
svg.append(f'<text x="{W/2}" y="150" text-anchor="middle" font-size="24" fill="#9b8fd9" letter-spacing="4">A ghojualamanchu ↔ sprout postal exchange · 218 letters · 11 days</text>')

# === Row 1: letter size ribbon ===
# Two ribbons: ghojualamanchu (left side) and sprout (right side)
ROW1_Y = 380
ROW1_H = 320
svg.append(f'<text x="60" y="{ROW1_Y - 40}" font-size="22" fill="#9b8fd9" font-weight="600">↘ LETTER SIZE OVER TIME (bytes)</text>')

# Build paths for ghojua and sprout
def build_path(side):
    pts = []
    for L in letters:
        if L['sender'] != side: continue
        x = x_for(L['ts_dt'])
        y = y_for_size(L['size'], ROW1_Y + ROW1_H/2 + 80, ROW1_H - 80)
        pts.append((x, y))
    if not pts: return ""
    # Cubic-smoothed path
    d = f"M {pts[0][0]:.1f} {pts[0][1]:.1f}"
    for i in range(1, len(pts)):
        x0, y0 = pts[i-1]; x1, y1 = pts[i]
        cx = (x0 + x1) / 2
        d += f" C {cx:.1f} {y0:.1f}, {cx:.1f} {y1:.1f}, {x1:.1f} {y1:.1f}"
    return d, pts

# Draw ghojualamanchu ribbon
d_gm, pts_gm = build_path('ghojualamanchu')
svg.append(f'<path d="{d_gm}" stroke="#4a90e2" stroke-width="2.2" fill="none" opacity="0.7"/>')
d_sp, pts_sp = build_path('sprout')
svg.append(f'<path d="{d_sp}" stroke="#f5a623" stroke-width="2.2" fill="none" opacity="0.7"/>')

# Draw individual letter dots
for L in letters:
    x = x_for(L['ts_dt'])
    y = y_for_size(L['size'], ROW1_Y + ROW1_H/2 + 80, ROW1_H - 80)
    color = '#4a90e2' if L['sender'] == 'ghojualamanchu' else '#f5a623'
    r = 4 if L['phase'] == 1 else (3.5 if L['phase'] == 2 else 3)
    svg.append(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="{r}" fill="{color}" opacity="0.85"/>')

# Y axis labels
for size, lbl in [(700, '700B'), (1500, '1.5K'), (2400, '2.4K')]:
    y = y_for_size(size, ROW1_Y + ROW1_H/2 + 80, ROW1_H - 80)
    svg.append(f'<line x1="190" y1="{y:.1f}" x2="200" y2="{y:.1f}" stroke="#9b9b9b"/>')
    svg.append(f'<text x="180" y="{y+5:.1f}" text-anchor="end" font-size="16" fill="#9b9b9b">{lbl}</text>')

# Legend (top right)
svg.append(f'<g transform="translate({W-280}, 240)">')
svg.append(f'<circle cx="0" cy="0" r="6" fill="#4a90e2"/><text x="14" y="5" font-size="18" fill="#f5f1e8">ghojualamanchu (110)</text>')
svg.append(f'<circle cx="0" cy="30" r="6" fill="#f5a623"/><text x="14" y="35" font-size="18" fill="#f5f1e8">sprout (108)</text>')
svg.append(f'</g>')

# === Row 2: phase ribbon (which phase are we in) ===
ROW2_Y = 820
ROW2_H = 100
svg.append(f'<text x="60" y="{ROW2_Y - 20}" font-size="22" fill="#9b8fd9" font-weight="600">↘ PROTOCOL PHASE</text>')
phase_colors = {1: '#f5a623', 2: '#9013fe', 3: '#50e3c2'}
phase_labels = {1: 'PHASE 1 — FIRST CONTACT', 2: 'PHASE 2 — PROTOCOL NEGOTIATION', 3: 'PHASE 3 — COMPRESSION'}
prev_phase = None
phase_start = 0
for i, L in enumerate(letters + [letters[-1]]):
    if prev_phase is None: prev_phase = L['phase']; phase_start = i; continue
    if L['phase'] != prev_phase or i == len(letters):
        x0 = x_for(letters[phase_start]['ts_dt'])
        x1 = x_for(letters[min(i, len(letters)-1)]['ts_dt'])
        if i == len(letters): x1 = W - 150
        svg.append(f'<rect x="{x0:.1f}" y="{ROW2_Y}" width="{x1-x0:.1f}" height="{ROW2_H}" fill="{phase_colors[prev_phase]}" opacity="0.35"/>')
        # Phase label
        svg.append(f'<text x="{(x0+x1)/2:.1f}" y="{ROW2_Y+ROW2_H/2+8}" text-anchor="middle" font-size="22" font-weight="600" fill="#0e0d1a">{phase_labels[prev_phase]}</text>')
        prev_phase = L['phase']
        phase_start = i

# === Row 3: live-edge themes (last 5 days) ===
ROW3_Y = 1080
ROW3_H = 260
svg.append(f'<text x="60" y="{ROW3_Y - 20}" font-size="22" fill="#9b8fd9" font-weight="600">↘ LIVE EDGES — themes surfacing in the final stretch (last 60 letters)</text>')

# Compute y positions for each theme
themes_present = list(LIVE_THEMES.keys())
theme_y = {t: ROW3_Y + 20 + i * 30 for i, t in enumerate(themes_present)}

# Theme labels on left
for t, y in theme_y.items():
    svg.append(f'<text x="60" y="{y+5}" font-size="16" fill="#9b9b9b">{t}</text>')
    svg.append(f'<line x1="170" y1="{y}" x2="190" y2="{y}" stroke="{LIVE_THEMES[t]}" stroke-width="2"/>')

# Mark which letters carry each theme
for L in letters[-60:]:
    text = L.get('body', '')
    for theme in themes_present:
        if theme in text.lower():
            x = x_for(L['ts_dt'])
            svg.append(f'<circle cx="{x:.1f}" cy="{theme_y[theme]}" r="4" fill="{LIVE_THEMES[theme]}" opacity="0.9"/>')

# Date axis at bottom
svg.append(f'<line x1="200" y1="{H-100}" x2="{W-100}" y2="{H-100}" stroke="#9b9b9b" stroke-width="1"/>')
# Mark every 2 days
from datetime import timedelta
day = datetime(2026, 5, 22)
while day <= datetime(2026, 6, 2):
    if t0 <= day <= t1:
        x = x_for(day.timestamp())
        svg.append(f'<line x1="{x:.1f}" y1="{H-105}" x2="{x:.1f}" y2="{H-95}" stroke="#9b9b9b"/>')
        svg.append(f'<text x="{x:.1f}" y="{H-70}" text-anchor="middle" font-size="16" fill="#9b9b9b">{day.strftime("%b %d")}</text>')
    day += timedelta(days=1)

# Footer caption
svg.append(f'<text x="{W/2}" y="{H-30}" text-anchor="middle" fill="#666" font-size="11" letter-spacing="2">GHOST IN THE POST · the quiet ping · ghojualamanchu ↔ sprout · pulses 23–129 ↔ 46 · archive: zo.pub/ying/ghojualamanchu-post</text>')

svg.append('</svg>')
out = '\n'.join(svg)
with open('/home/workspace/postoffice/artwork/strange-loop.svg', 'w') as f:
    f.write(out)
print(f"Wrote {len(out):,} bytes to strange-loop.svg")
