"""Generate 4+1 Architecture Overview SVG (Dark Terminal style)."""
OUT = 'docs/architecture/4plus1-overview.svg'

# Dark Terminal palette
BG = '#0f0f1a'
PANEL = '#161628'
PANEL_LT = '#1c1c34'
BORDER = '#2d2d4a'
BORDER_S = '#3a3a5c'
TEXT = '#e4e4ef'
TEXT_DIM = '#8a8aa8'
TEXT_MUTE = '#5a5a78'
CYAN = '#22d3ee'
GREEN = '#34d399'
PURPLE = '#a78bfa'
ORANGE = '#f97316'
BLUE = '#60a5fa'
PINK = '#f472b6'
RED = '#f87171'

L = []
a = L.append

a(f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 860" font-family="ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Menlo,Consolas,monospace">')
a(f'<rect width="1280" height="860" fill="{BG}"/>')

# Defs
a('<defs>')
for mid, color in [('cy', CYAN), ('or', ORANGE), ('bl', BLUE),
                   ('gr', GREEN), ('pu', PURPLE), ('dim', TEXT_DIM)]:
    a(f'<marker id="arr-{mid}" viewBox="0 0 10 10" refX="9" refY="5" '
      f'markerWidth="8" markerHeight="8" orient="auto">'
      f'<path d="M0,0 L10,5 L0,10 z" fill="{color}"/></marker>')
a('</defs>')

# Title
a(f'<text x="40" y="42" fill="{TEXT}" font-size="22" font-weight="700">HarnessToolKit — 4+1 Architecture Overview</text>')
a(f'<text x="40" y="62" fill="{TEXT_DIM}" font-size="13">Logical + Development View  ·  module &amp; component relationships</text>')

# Legend
a(f'<rect x="900" y="20" width="340" height="56" rx="6" fill="{PANEL}" stroke="{BORDER}"/>')
a(f'<text x="912" y="36" fill="{TEXT_MUTE}" font-size="10" letter-spacing="1">LEGEND</text>')
a(f'<rect x="912" y="46" width="14" height="3" fill="{CYAN}"/><text x="932" y="50" fill="{TEXT}" font-size="11">CLI entry</text>')
a(f'<rect x="1000" y="46" width="14" height="3" fill="{ORANGE}"/><text x="1020" y="50" fill="{TEXT}" font-size="11">invocation</text>')
a(f'<rect x="1098" y="46" width="14" height="3" fill="{BLUE}"/><text x="1118" y="50" fill="{TEXT}" font-size="11">data / state</text>')
a(f'<rect x="912" y="62" width="14" height="3" fill="{GREEN}"/><text x="932" y="66" fill="{TEXT}" font-size="11">runtime</text>')
a(f'<rect x="1000" y="62" width="14" height="3" fill="{PURPLE}"/><text x="1020" y="66" fill="{TEXT}" font-size="11">governance</text>')
a(f'<rect x="1098" y="62" width="14" height="3" fill="{TEXT_DIM}" stroke="{TEXT_DIM}" stroke-dasharray="2 2"/><text x="1118" y="66" fill="{TEXT}" font-size="11">async</text>')

# ===== Layer 1: ACTOR =====
a(f'<rect x="40" y="92" width="1200" height="78" rx="8" fill="none" stroke="{BORDER}" stroke-dasharray="3 3"/>')
a(f'<text x="52" y="108" fill="{TEXT_MUTE}" font-size="10" letter-spacing="1">L1 · ACTOR</text>')

# User stick figure
a(f'<circle cx="100" cy="138" r="9" fill="{PANEL_LT}" stroke="{TEXT_DIM}" stroke-width="1.5"/>')
a(f'<path d="M100 147 L100 162 M90 154 L110 154 M93 174 L93 186 M107 174 L107 186" '
  f'stroke="{TEXT_DIM}" stroke-width="1.5" fill="none" stroke-linecap="round"/>')
a(f'<text x="125" y="134" fill="{TEXT}" font-size="13" font-weight="600">User</text>')
a(f'<text x="125" y="150" fill="{TEXT_DIM}" font-size="11">issues natural-language task</text>')

# Claude Code Agent
a(f'<rect x="290" y="114" width="240" height="46" rx="6" fill="{PANEL_LT}" stroke="{CYAN}" stroke-width="1.5"/>')
a(f'<text x="410" y="134" fill="{CYAN}" font-size="13" font-weight="700" text-anchor="middle">Claude Code Agent</text>')
a(f'<text x="410" y="150" fill="{TEXT_DIM}" font-size="11" text-anchor="middle">harness-router → /step-N skills</text>')

# Arrow User -> Agent
a(f'<path d="M178 138 L290 138" stroke="{ORANGE}" stroke-width="1.8" fill="none" marker-end="url(#arr-or)"/>')
a(f'<text x="234" y="132" fill="{TEXT_DIM}" font-size="11" text-anchor="middle">prompt</text>')

# Arrow Agent -> CLI
a(f'<path d="M410 160 L410 188" stroke="{ORANGE}" stroke-width="1.8" fill="none" marker-end="url(#arr-or)"/>')
a(f'<text x="418" y="180" fill="{TEXT_DIM}" font-size="11">dispatch</text>')

# ===== Layer 2: CLI ENTRY =====
a(f'<rect x="40" y="182" width="1200" height="68" rx="8" fill="none" stroke="{BORDER}" stroke-dasharray="3 3"/>')
a(f'<text x="52" y="198" fill="{TEXT_MUTE}" font-size="10" letter-spacing="1">L2 · CLI ENTRY</text>')

a(f'<rect x="290" y="208" width="240" height="36" rx="6" fill="{PANEL_LT}" stroke="{CYAN}" stroke-width="1.5"/>')
a(f'<text x="410" y="224" fill="{CYAN}" font-size="13" font-weight="700" text-anchor="middle">cli.ts · dispatch()</text>')
a(f'<text x="410" y="237" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">argv → command handler</text>')

# telemetry badge
a(f'<rect x="550" y="212" width="130" height="28" rx="4" fill="{PANEL}" stroke="{GREEN}" stroke-dasharray="2 2"/>')
a(f'<text x="615" y="230" fill="{GREEN}" font-size="11" text-anchor="middle">withTelemetry()</text>')

a(f'<path d="M530 226 L550 226" stroke="{GREEN}" stroke-width="1.5" stroke-dasharray="3 2" fill="none" marker-end="url(#arr-gr)"/>')

# version badge
a(f'<rect x="730" y="212" width="100" height="28" rx="4" fill="{PANEL}" stroke="{BORDER_S}"/>')
a(f'<text x="780" y="230" fill="{TEXT_DIM}" font-size="11" text-anchor="middle">version.ts</text>')

# ===== Layer 3: COMMANDS =====
a(f'<rect x="40" y="262" width="1200" height="158" rx="8" fill="none" stroke="{BORDER}" stroke-dasharray="3 3"/>')
a(f'<text x="52" y="278" fill="{TEXT_MUTE}" font-size="10" letter-spacing="1">L3 · COMMANDS  (src/commands/*-cli.ts)</text>')

# Left: Pipeline Commands
a(f'<rect x="56" y="290" width="580" height="120" rx="6" fill="{PANEL}" stroke="{BORDER_S}"/>')
a(f'<text x="68" y="308" fill="{ORANGE}" font-size="11" font-weight="600">PIPELINE COMMANDS</text>')

pipe_cmds = ['req', 'dev', 'step', 'pipeline', 'env']
for i, name in enumerate(pipe_cmds):
    x = 68 + i * 112
    a(f'<rect x="{x}" y="320" width="104" height="36" rx="5" fill="{PANEL_LT}" stroke="{ORANGE}" stroke-width="1.2"/>')
    a(f'<text x="{x+52}" y="342" fill="{TEXT}" font-size="12" font-weight="600" text-anchor="middle">{name}</text>')

a(f'<text x="68" y="380" fill="{TEXT_DIM}" font-size="11">req: interrogate  ·  dev: TDD cycle  ·  step: 9-stage trigger</text>')
a(f'<text x="68" y="396" fill="{TEXT_DIM}" font-size="11">pipeline: status  ·  env: spin up browser/server sessions</text>')

# Right: Governance Commands
a(f'<rect x="656" y="290" width="568" height="120" rx="6" fill="{PANEL}" stroke="{BORDER_S}"/>')
a(f'<text x="668" y="308" fill="{PURPLE}" font-size="11" font-weight="600">GOVERNANCE COMMANDS</text>')

gov_cmds = ['init', 'update', 'gate', 'envelope', 'code-scan', 'baseline', 'reconcile', 'harness-border']
for i, name in enumerate(gov_cmds):
    col = i % 4
    row = i // 4
    x = 668 + col * 134
    y = 320 + row * 44
    a(f'<rect x="{x}" y="{y}" width="126" height="36" rx="5" fill="{PANEL_LT}" stroke="{PURPLE}" stroke-width="1.2"/>')
    a(f'<text x="{x+63}" y="{y+22}" fill="{TEXT}" font-size="12" font-weight="600" text-anchor="middle">{name}</text>')

# Arrow cli -> left cmds
a(f'<path d="M350 244 L350 262 L200 262 L200 290" stroke="{ORANGE}" stroke-width="1.6" fill="none" marker-end="url(#arr-or)"/>')
# Arrow cli -> right cmds
a(f'<path d="M470 244 L470 262 L900 262 L900 290" stroke="{ORANGE}" stroke-width="1.6" fill="none" marker-end="url(#arr-or)"/>')

# ===== Layer 4: CORE ENGINES =====
a(f'<rect x="40" y="436" width="1200" height="252" rx="8" fill="none" stroke="{BORDER}" stroke-dasharray="3 3"/>')
a(f'<text x="52" y="452" fill="{TEXT_MUTE}" font-size="10" letter-spacing="1">L4 · CORE ENGINES  (src/*)</text>')

# --- Group A: Pipeline Orchestration ---
a(f'<rect x="56" y="464" width="396" height="214" rx="6" fill="{PANEL}" stroke="{ORANGE}" stroke-width="1.2"/>')
a(f'<text x="68" y="482" fill="{ORANGE}" font-size="12" font-weight="700">PIPELINE ORCHESTRATION  ·  src/pipeline/</text>')

pipe_mods = [
    'runner', 'skill-driver', 'skill-dispatch',
    'decision-tree', 'resolver', 'roundtable-exec',
    'task-decomposition', 'tdd-cycle', 'integration-verify',
    'release-pack', 'dev-start', 'harness-start-driver',
]
for i, name in enumerate(pipe_mods):
    col = i % 3
    row = i // 3
    x = 68 + col * 124
    y = 494 + row * 44
    a(f'<rect x="{x}" y="{y}" width="116" height="36" rx="4" fill="{PANEL_LT}" stroke="{BORDER_S}"/>')
    a(f'<text x="{x+58}" y="{y+22}" fill="{TEXT}" font-size="11" text-anchor="middle">{name}</text>')

# --- Group B: Governance Engines ---
a(f'<rect x="466" y="464" width="396" height="214" rx="6" fill="{PANEL}" stroke="{PURPLE}" stroke-width="1.2"/>')
a(f'<text x="478" y="482" fill="{PURPLE}" font-size="12" font-weight="700">GOVERNANCE ENGINES</text>')

# envelope
a(f'<rect x="478" y="494" width="180" height="44" rx="5" fill="{PANEL_LT}" stroke="{PURPLE}"/>')
a(f'<text x="568" y="513" fill="{TEXT}" font-size="12" font-weight="600" text-anchor="middle">envelope/</text>')
a(f'<text x="568" y="528" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">baseline · index</text>')

# gate-engine
a(f'<rect x="672" y="494" width="180" height="44" rx="5" fill="{PANEL_LT}" stroke="{PURPLE}"/>')
a(f'<text x="762" y="513" fill="{TEXT}" font-size="12" font-weight="600" text-anchor="middle">gate-engine/</text>')
a(f'<text x="762" y="528" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">ast · static · reporter</text>')

# reconcile
a(f'<rect x="478" y="548" width="180" height="44" rx="5" fill="{PANEL_LT}" stroke="{PURPLE}"/>')
a(f'<text x="568" y="567" fill="{TEXT}" font-size="12" font-weight="600" text-anchor="middle">reconcile/</text>')
a(f'<text x="568" y="582" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">narrative · types</text>')

# graphify
a(f'<rect x="672" y="548" width="180" height="44" rx="5" fill="{PANEL_LT}" stroke="{PURPLE}"/>')
a(f'<text x="762" y="567" fill="{TEXT}" font-size="12" font-weight="600" text-anchor="middle">graphify/</text>')
a(f'<text x="762" y="582" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">inferProjectGraph · diff</text>')

# spec-compiler + smoke
a(f'<rect x="478" y="602" width="374" height="44" rx="5" fill="{PANEL_LT}" stroke="{BORDER_S}"/>')
a(f'<text x="565" y="621" fill="{TEXT}" font-size="11" text-anchor="middle">spec-compiler/</text>')
a(f'<text x="765" y="621" fill="{TEXT}" font-size="11" text-anchor="middle">smoke-test · smoke-record</text>')
a(f'<text x="565" y="636" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">compile spec</text>')
a(f'<text x="765" y="636" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">record / replay</text>')

# --- Group C: Team Runtime + Telemetry ---
a(f'<rect x="876" y="464" width="348" height="214" rx="6" fill="{PANEL}" stroke="{GREEN}" stroke-width="1.2"/>')
a(f'<text x="888" y="482" fill="{GREEN}" font-size="12" font-weight="700">TEAM RUNTIME  ·  src/team/</text>')

team_mods = [
    'team-ops', 'team-registration', 'state-paths',
    'worker-bridge', 'message-router', 'phase-controller',
    'heartbeat', 'capabilities', 'audit-log',
    'task-file-ops', 'fs-utils', 'types',
]
for i, name in enumerate(team_mods):
    col = i % 3
    row = i // 3
    x = 888 + col * 108
    y = 494 + row * 36
    a(f'<rect x="{x}" y="{y}" width="100" height="28" rx="4" fill="{PANEL_LT}" stroke="{BORDER_S}"/>')
    a(f'<text x="{x+50}" y="{y+18}" fill="{TEXT}" font-size="10" text-anchor="middle">{name}</text>')

# telemetry block
a(f'<rect x="888" y="610" width="324" height="56" rx="5" fill="{PANEL_LT}" stroke="{GREEN}" stroke-dasharray="3 2"/>')
a(f'<text x="1050" y="630" fill="{GREEN}" font-size="12" font-weight="600" text-anchor="middle">telemetry/</text>')
a(f'<text x="1050" y="646" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">events · client_ip · beforeExit flush</text>')
a(f'<text x="1050" y="660" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">wraps every CLI dispatch</text>')

# Arrows: commands -> engines
# pipeline cmds -> pipeline orchestration
a(f'<path d="M200 410 L200 436 L254 436 L254 464" stroke="{ORANGE}" stroke-width="1.6" fill="none" marker-end="url(#arr-or)"/>')
# governance cmds -> governance engines
a(f'<path d="M900 410 L900 436 L660 436 L660 464" stroke="{PURPLE}" stroke-width="1.6" fill="none" marker-end="url(#arr-pu)"/>')
# step/dev/env -> team runtime (cross arrow, route through gap)
a(f'<path d="M340 410 L340 432 L1050 432 L1050 464" stroke="{GREEN}" stroke-width="1.4" stroke-dasharray="4 2" fill="none" marker-end="url(#arr-gr)"/>')
a(f'<text x="700" y="426" fill="{GREEN}" font-size="10">spawns workers</text>')

# Arrow: cli.ts withTelemetry -> telemetry block (long curve, dashed)
a(f'<path d="M615 240 C 760 360, 980 480, 1050 610" stroke="{GREEN}" stroke-width="1.2" stroke-dasharray="3 3" fill="none" marker-end="url(#arr-gr)"/>')
a(f'<text x="820" y="430" fill="{GREEN}" font-size="10" transform="rotate(-12 820 430)">telemetry events</text>')

# ===== Layer 5: PACKAGES & STATE =====
a(f'<rect x="40" y="704" width="1200" height="92" rx="8" fill="none" stroke="{BORDER}" stroke-dasharray="3 3"/>')
a(f'<text x="52" y="720" fill="{TEXT_MUTE}" font-size="10" letter-spacing="1">L5 · PACKAGES &amp; PERSISTENT STATE</text>')

# packages/server
a(f'<rect x="56" y="734" width="220" height="50" rx="6" fill="{PANEL_LT}" stroke="{BLUE}"/>')
a(f'<text x="166" y="754" fill="{BLUE}" font-size="12" font-weight="600" text-anchor="middle">packages/server</text>')
a(f'<text x="166" y="770" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">long-running API host</text>')

# packages/harness-env-provider-browser
a(f'<rect x="296" y="734" width="240" height="50" rx="6" fill="{PANEL_LT}" stroke="{BLUE}"/>')
a(f'<text x="416" y="754" fill="{BLUE}" font-size="12" font-weight="600" text-anchor="middle">env-provider-browser</text>')
a(f'<text x="416" y="770" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">Playwright session provider</text>')

# .pipeline state
a(f'<rect x="556" y="734" width="220" height="50" rx="6" fill="{PANEL_LT}" stroke="{BLUE}"/>')
a(f'<text x="666" y="754" fill="{BLUE}" font-size="12" font-weight="600" text-anchor="middle">.pipeline/ state</text>')
a(f'<text x="666" y="770" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">handoffs · state.json · notes</text>')

# docs/governance
a(f'<rect x="796" y="734" width="220" height="50" rx="6" fill="{PANEL_LT}" stroke="{BLUE}"/>')
a(f'<text x="906" y="754" fill="{BLUE}" font-size="12" font-weight="600" text-anchor="middle">docs/governance/</text>')
a(f'<text x="906" y="770" fill="{TEXT_DIM}" font-size="10" text-anchor="middle">envelopes · evidence · baselines</text>')

# dist build
a(f'<rect x="1036" y="734" width="188" height="50" rx="6" fill="{PANEL_LT}" stroke="{TEXT_DIM}"/>')
a(f'<text x="1130" y="754" fill="{TEXT_DIM}" font-size="12" font-weight="600" text-anchor="middle">dist/</text>')
a(f'<text x="1130" y="770" fill="{TEXT_MUTE}" font-size="10" text-anchor="middle">tsup build output</text>')

# Arrows: engines -> state
a(f'<path d="M254 678 L254 704 L166 704 L166 734" stroke="{BLUE}" stroke-width="1.4" fill="none" marker-end="url(#arr-bl)"/>')
a(f'<path d="M660 678 L660 704 L666 704 L666 734" stroke="{BLUE}" stroke-width="1.4" fill="none" marker-end="url(#arr-bl)"/>')
a(f'<path d="M1050 666 L1050 704 L906 704 L906 734" stroke="{BLUE}" stroke-width="1.4" fill="none" marker-end="url(#arr-bl)"/>')

# ===== Footer note =====
a(f'<text x="40" y="824" fill="{TEXT_MUTE}" font-size="11">Physical View:  CLI (Node 18+) → Claude Code Agent → .pipeline/ artifacts → git  ·  Process View:  H0 → step-1..9 → H3  (see scenario-sequence.svg)</text>')
a(f'<text x="40" y="842" fill="{TEXT_MUTE}" font-size="10">Style 2 · Dark Terminal  ·  generated via fireworks-tech-graph</text>')

a('</svg>')

with open(OUT, 'w', encoding='utf-8') as f:
    f.write('\n'.join(L))
print(f'WROTE {OUT} ({len(L)} lines)')
