"""Render the research diagrams as PNG, SVG, and editable Mermaid files."""
from pathlib import Path
import os
os.environ.setdefault("MPLCONFIGDIR", "/tmp/tenex-matplotlib")
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch

ROOT = Path(__file__).resolve().parent
BLUE = "#e6f0fb"
GREEN = "#e2f3e8"
AMBER = "#fff0d6"
GRAY = "#eef1f5"
INK = "#23354b"


def render(name, title, subtitle, nodes, edges, width=16, height=10, footer="Conceptual reconstruction from public sources. Arrows do not establish internal APIs."):
    fig, ax = plt.subplots(figsize=(width, height), dpi=150)
    ax.set(xlim=(0, 16), ylim=(0, 10))
    ax.axis("off")
    fig.patch.set_facecolor("white")
    ax.text(.3, 9.65, title, fontsize=21, weight="bold", color=INK, va="top")
    ax.text(.3, 9.08, subtitle, fontsize=11, color="#52657a", va="top")
    boxes = {}
    for key, text, x, y, w, h, color in nodes:
        box = FancyBboxPatch((x-w/2, y-h/2), w, h, boxstyle="round,pad=0.08,rounding_size=0.12",
                             fc=color, ec="#8494a7", lw=1.1, zorder=3)
        ax.add_patch(box)
        boxes[key] = (x, y, w, h, text)
        ax.text(x, y, text, ha="center", va="center", fontsize=12, color=INK, linespacing=1.55, zorder=4)
    mermaid = ["flowchart TB"]
    for key, (x, y, w, h, text) in boxes.items():
        label = text.replace("\n", " / ").replace('"', "'")
        mermaid.append(f'    {key}["{label}"]')
    for a, b, label, dashed, curve, *label_position in edges:
        xa, ya, wa, ha, _ = boxes[a]
        xb, yb, wb, hb, _ = boxes[b]
        dx, dy = xb-xa, yb-ya
        def boundary(x, y, w, h, dx, dy):
            scale = min((w/2+.09)/abs(dx) if dx else 1e9, (h/2+.09)/abs(dy) if dy else 1e9)
            return x+dx*scale, y+dy*scale
        start = boundary(xa, ya, wa, ha, dx, dy)
        end = boundary(xb, yb, wb, hb, -dx, -dy)
        arrow = FancyArrowPatch(start, end, arrowstyle="-|>", mutation_scale=15, lw=1.5,
                                color="#62748c", linestyle="--" if dashed else "-",
                                connectionstyle=f"arc3,rad={curve}", zorder=2)
        ax.add_patch(arrow)
        if label:
            lx, ly = (start[0]+end[0])/2, (start[1]+end[1])/2
            lx += curve*dy*.45
            ly -= curve*dx*.45
            if label_position:
                lx, ly = label_position[0]
            ax.text(lx, ly, label, ha="center", va="center", fontsize=10, color=INK, zorder=5,
                    bbox=dict(boxstyle="round,pad=.2", fc="white", ec="none", alpha=.96))
        if dashed:
            mermaid.append(f'    {a} -. {label.replace(chr(10), " / ") or "inferred dependency"} .-> {b}')
        else:
            mermaid.append(f'    {a} -->{("|" + label.replace(chr(10), " / ") + "|") if label else ""} {b}')
    ax.text(.3, .2, footer, fontsize=10, color="#52657a", va="bottom")
    fig.subplots_adjust(left=.02, right=.98, bottom=.03, top=.99)
    for ext in ("png", "svg"):
        fig.savefig(ROOT / f"{name}.{ext}", facecolor="white")
    plt.close(fig)
    (ROOT / f"{name}.mmd").write_text("\n".join(mermaid)+"\n")

render("data-flow", "From a business problem to a measured result", "Sources: S02, S11, S26. Conceptual service flow. Human experts coordinate the work.", [
 ("people", "Sponsor and employees\nGoals, tasks, examples", 3,7.7,4.8,1.1,BLUE),
 ("discovery", "Surveys and interviews\nPain, evidence, baseline", 12.5,7.7,5,1.1,BLUE),
 ("plan", "Expert review and roadmap\nOwner, scope, dependencies", 12.5,5.3,5,1.1,AMBER),
 ("tools", "Purchased tools or custom code\nControls and acceptance criteria", 12.5,2.9,5,1.1,GRAY),
 ("use", "Workflow owner and team\nUse, review, corrections", 3,2.9,4.8,1.1,GREEN),
 ("measure", "Compare with the baseline\nExpand, revise, or stop", 3,5.3,4.8,1.1,AMBER),
], [
 ("people","discovery","",False,0), ("discovery","plan","",False,0),
 ("plan","tools","approved scope",False,0), ("tools","use","software and instruction",False,0),
 ("use","measure","results",False,0), ("measure","plan","feedback",False,0),
], footer="The service produces reports, plans, and software. A prototype or completed ticket does not prove a business return.")

render("architecture", "MetaHarness: one project record, several views", "Source: S07. Disclosed logical responsibilities. Internal service topology remains unknown.", [
 ("people", "Engineers and agents", 3,7.8,4.6,1.0,BLUE),
 ("session", "Startup context\nVersioned skills", 12.5,7.8,4.7,1.0,GREEN),
 ("record", "Git project record\nFacts, intent, history", 7.8,5.5,5,1.1,GRAY),
 ("cli", "CLI\nValidate, preview, apply", 7.8,3,5,1.1,AMBER),
 ("os", "Tenex OS\nDerived health", 2.7,3,4.3,1.1,BLUE),
 ("tracker", "Linear and GitHub\nIDs, status, metadata", 13.1,3,4.5,1.1,BLUE),
], [
 ("session","people","",False,0), ("record","session","",False,0),
 ("people","record","",False,0), ("record","os","",False,0),
 ("record","cli","",False,0), ("cli","tracker","",False,0),
 ("tracker","record","fenced sync only",False,-.36,(11.8,4.2)),
], footer="Human prose and machine metadata have separate write boundaries. Completion requires evidence.")

render("evaluation-cycle", "A production failure becomes a regression case", "Source: S08. Published evaluation method. No measured Tenex performance result.", [
 ("trace", "Production trace\nInput, steps, result", 3,7.7,4.8,1.1,BLUE),
 ("case", "Flagged failure\nSafe case and correct behavior", 12.5,7.7,5,1.1,AMBER),
 ("reproduce", "Offline run\nReproduce the failure", 12.5,5.3,5,1.1,GRAY),
 ("change", "Agent change\nRepeat case and full dataset", 12.5,2.9,5,1.1,GRAY),
 ("check", "Code and model graders\nCheck actions and answers", 3,2.9,4.8,1.1,AMBER),
 ("release", "Checked version\nObserve production behavior", 3,5.3,4.8,1.1,GREEN),
], [
 ("trace","case","",False,0), ("case","reproduce","",False,0),
 ("reproduce","change","",False,0), ("change","check","",False,0),
 ("check","release","pass",False,0), ("release","trace","",False,0),
 ("check","change","fail",False,-.3,(7.7,3.7)),
], footer="Offline tests need historical tool state and safe writes. The article leaves those implementation details for later work.")

render("customer-health", "Customer health: signals, a brief, and human action", "Source: S12. Tenex's described workflow. No independently measured retention result.", [
 ("reactive", "On demand\nClaude queries Linear", 3,7.8,4.7,1.1,BLUE),
 ("sources", "Scheduled inputs\nLinear, Slack, call transcripts", 12.5,7.8,5,1.1,BLUE),
 ("human", "Strategist\nInvestigate delivery signals", 3,5.4,4.7,1.1,AMBER),
 ("brief", "Zapier agent\nCustomer health brief", 12.5,5.4,5,1.1,GRAY),
 ("draft", "Separate Zapier agent\nGmail drafts from action items", 12.5,3,5,1.1,GRAY),
 ("review", "Human review\nEdit and send", 3,3,4.7,1.1,AMBER),
], [
 ("reactive","human","delivery signal",False,0), ("sources","brief","",False,0),
 ("brief","draft","action items",False,0), ("draft","review","drafts only",False,0),
 ("brief","human","risk signal",False,0),
], footer="The score is directional. The final agent saves drafts. Its prompt prohibits automatic sends.")
