# -*- coding: utf-8 -*-
"""Generate the Vibe Math V2 framework diagram (架构图) as a PNG poster.
Output: 示例图/框架图-v2.png   (run from anywhere: python docs/generate_framework_diagram_v2.py)
Layout: left = pipeline (交互/调度/子代理·方向/子代理·验证/收口), right = 数据层 aligned by stage.
"""
import matplotlib
matplotlib.use("Agg")
import os
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, Rectangle, FancyArrowPatch

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei"]
plt.rcParams["axes.unicode_minus"] = False

BASE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(BASE)
OUT = os.path.join(ROOT, "示例图", "框架图-v2.png")

fig = plt.figure(figsize=(18, 11.5))
ax = fig.add_axes([0, 0, 1, 1])
ax.axis("off")
ax.set_xlim(0, 18)
ax.set_ylim(0, 11.5)

def box(x0, y0, w, h, fc, ec="#37474F", lw=1.6, rounding=0.16, z=3):
    ax.add_patch(FancyBboxPatch((x0, y0), w, h,
                 boxstyle=f"round,pad=0.10,rounding_size={rounding}",
                 facecolor=fc, edgecolor=ec, linewidth=lw, zorder=z))

def txt(cx, cy, s, fs=11, color="#263238", weight="normal", z=5):
    ax.text(cx, cy, s, ha="center", va="center", fontsize=fs, color=color,
            fontweight=weight, linespacing=1.45, zorder=z)

def arrow(x1, y1, x2, y2, label=None, lx=0, ly=0.24, ls=9.5, rad=0.0,
          style="->", lw=1.8, color="#455A64", dashed=False, z=4):
    ax.add_patch(FancyArrowPatch((x1, y1), (x2, y2), arrowstyle=style,
                 mutation_scale=17, linewidth=lw, color=color, zorder=z,
                 connectionstyle=f"arc3,rad={rad}",
                 linestyle="--" if dashed else "-"))
    if label:
        ax.text((x1 + x2) / 2 + lx, (y1 + y2) / 2 + ly, label, fontsize=ls,
                ha="center", va="center", color="#333",
                bbox=dict(fc="white", ec="none", alpha=0.85, pad=1.0), zorder=6)

def band(x0, y0, x1, y1, fc, title, tc="#607D8B"):
    ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, facecolor=fc,
                           edgecolor="none", alpha=0.5, zorder=1))
    # title pinned to the band's top-left corner, drawn ABOVE the boxes, with a
    # white backing so it is never obscured by the rectangles
    ax.text(x0 + 0.35, y1 - 0.12, title, fontsize=11.5, color=tc,
            fontweight="bold", ha="left", va="top", zorder=6,
            bbox=dict(fc="white", ec="none", alpha=0.85, pad=1.2))

# ── title ────────────────────────────────────────────────────────────────
ax.text(9, 11.12, "Vibe Math V2 — 多代理数学问题求解与验证框架（概率驱动）", fontsize=21,
        ha="center", va="center", color="#1A237E", fontweight="bold")
ax.text(9, 10.66, "qs.json 问题清单 + Propos/ 命题库  ·  按正确概率/价值调度  ·  explorer → 逐方向 solver → 多验证器辩论裁决",
        fontsize=10.5, ha="center", va="center", color="#555")

# ── layer bands ──────────────────────────────────────────────────────────
band(0.3, 9.45, 17.7, 10.45, "#E3F2FD", "交互层")
band(0.3, 7.70, 17.7, 8.95, "#FFF8E1", "调度层 · 插件代码")
band(0.3, 5.95, 17.7, 7.20, "#E8F5E9", "子代理层 · 方向求解")
band(0.3, 4.20, 17.7, 5.45, "#E8F5E9", "子代理层 · 交叉验证")
band(0.3, 1.50, 17.7, 4.00, "#F3E5F5", "收口 · 回写 · 数据层")

# ── left pipeline (x 1.0–8.0) ────────────────────────────────────────────
box(1.0, 9.60, 7.0, 0.75, "#BBDEFB")
txt(4.5, 9.98, "用户 · 主代理（助手 + 汇报者）\n自然语言 · 翻译需求/汇报/配置 · 不求解不调度", fs=11)
box(1.0, 7.85, 7.0, 0.95, "#FFE0B2")
txt(4.5, 8.33, "调度器（插件代码 · 概率驱动）\n唯一文件写者 · 按优先级调度 · 状态机 · 断点持久化", fs=11)
box(1.0, 6.10, 7.0, 0.95, "#C8E6C9")
txt(4.5, 6.58, "Explorer → Solver × N\n拆方向（全死路→重派生）· 逐方向多轮迭代", fs=11)
box(1.0, 4.35, 7.0, 0.95, "#C8E6C9")
txt(4.5, 4.83, "Verifier × ≥3（严苛审稿人）\n独立审查 → 辩论（交流群）→ 裁决（flat/forced）", fs=11)
box(1.0, 2.60, 7.0, 0.95, "#C8E6C9")
txt(4.5, 3.08, "概率 = 1 → 收口\n问题 solved · 命题 1/0 · 优先级 never", fs=11)

# ── right data boxes (x 10.2–17.0) ───────────────────────────────────────
box(10.2, 7.85, 6.8, 0.95, "#E1BEE7")
txt(13.6, 8.33, "qs/qs.json\n问题清单 + 解法（正确概率）", fs=10.5)
box(10.2, 6.10, 6.8, 0.95, "#E1BEE7")
txt(13.6, 6.58, "Propos/&lt;分类&gt;_Propos.json\n命题：布尔估计 · 证明/证伪列表", fs=10.5)
box(10.2, 4.35, 6.8, 0.95, "#E1BEE7")
txt(13.6, 4.83, "Verified/\n定论事实（布尔估计 0/1）", fs=10.5)
box(10.2, 2.90, 6.8, 0.70, "#E1BEE7")
txt(13.6, 3.25, "Verification_logs/ · Progress_Logs/\n辩论记录 · 进度报告", fs=10)
box(10.2, 1.60, 6.8, 0.70, "#E1BEE7")
txt(13.6, 1.95, "Reliable/\n可信参考文献（只读）", fs=10)

# ── pipeline arrows ──────────────────────────────────────────────────────
arrow(4.5, 9.60, 4.5, 8.80, "vibe_math_* 工具", ly=0.26)
arrow(4.5, 7.85, 4.5, 7.05, "① 按优先级取问题 · 派 Explorer / 每方向 Solver", ly=0.24)
arrow(4.5, 6.10, 4.5, 5.30, "④ 选 r（命题 / 命题+证明·证伪 / 问题+解法）派 ≥3 验证器", ly=0.24)
arrow(4.5, 4.35, 4.5, 3.55, "⑤ 裁决 0/1/中间 → ⑥ 概率=1 收口", ly=0.24)
arrow(0.55, 3.08, 0.55, 8.33, "读取 qs / 已解决回写", lx=0.85, ly=0)

# ── stage↔data links ─────────────────────────────────────────────────────
arrow(8.0, 8.33, 10.2, 8.33, "读写 qs.json", ly=0.28, style="<|-|>")
arrow(8.0, 6.58, 10.2, 6.58, "② 引理/解法写入（概率<1）", ly=0.28)
arrow(10.2, 6.30, 8.1, 4.90, "③ 命题/证明 → 验证", ly=0.24, rad=-0.15)
arrow(8.0, 4.83, 10.2, 4.83, "⑥ 定论 → 晋升/证伪", ly=0.28)
arrow(7.9, 4.40, 10.3, 3.60, "辩论记录", ly=0.24, rad=-0.1)

# ── feature strip ────────────────────────────────────────────────────────
feat = ["概率=1 自动收口（solved / 1|0）", "never = 永不调度 · 不阻塞终止",
        "断点续跑（resume · 进程纪元）", "reportMode file|push|both · 按项目隔离"]
fx = [0.6, 5.0, 9.4, 13.8]
for x0, s in zip(fx, feat):
    box(x0, 0.40, 3.9, 0.72, "#ECEFF1", lw=1.2, rounding=0.2)
    txt(x0 + 1.95, 0.76, s, fs=9.5)

plt.savefig(OUT, dpi=170, bbox_inches="tight", facecolor="white")
print("saved " + OUT)
