"""§2 场景 A · 明信片 Happy Path · slide 28-41 (14 内容页) · v0.2 真实内容版

嵌入 8 张图（D1/C1/A14/A3/D2/C5/A9/C2/F1）+ 引用 4 份样例 md（00-prd/01-adr/02-dispatch/03-progress）
"""

from pathlib import Path
from pptx.util import Inches, Pt
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR

from build_main import (
    _fill_ph, _add_textbox, _add_card,
    NAVY, CORAL, CORAL_LIGHT, BLUE_ACCENT, GREEN, GOLD,
    GRAY_300, GRAY_500, GRAY_700, WHITE,
)
from build_sec_M1 import _add_centered_image, _title


def build_slide_28_14_teammates(prs):
    """slide 28: 14 同事卡片墙 · 嵌入 D1"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · 14 同事一览（明信片 feature 出场 8 人）")
    _add_centered_image(s, "D1-fourteen-teammates.png")
    return s


def build_slide_29_scrum_roles(prs):
    """slide 29: Scrum 三角色映射 · v1.3 改 PPT 自画 3 行映射表
    布局：3 行（每行 = Scrum 标准卡 → 箭头 → AGF 实际卡 + 合并理由）
    解决 v1.2 drawio C1 的箭头交叉 + 文字遮挡问题
    """
    from pptx.enum.shapes import MSO_SHAPE as _MS
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · Scrum 三角色 → AGF 实际 · 一对一映射")

    # 表头行
    headers = [
        (0.55, 4.1,  "Scrum Guide 2025 标准（3 角色）",  NAVY),
        (5.6,  1.2,  "→",                                CORAL),
        (7.1,  4.4,  "AGF 团队实际",                      CORAL),
    ]
    for (x, w, text, c) in headers:
        _add_textbox(s, Inches(x), Inches(1.45), Inches(w), Inches(0.4),
                     text, size_pt=15, bold=True, color=c, align=PP_ALIGN.CENTER)

    # 3 行映射数据
    rows = [
        # (scrum_role, scrum_color, scrum_dut, agf_role, agf_color, agf_dut, merge_reason)
        ("Product Owner",  GOLD,
         "定 why / who / what · 管 backlog 优先级 · 对业务价值负责",
         "product-lead （保留 PO 职责）", CORAL,
         "唯一流程编排者 · 写 PRD + 派单 + 业务签字",
         "保留"),
        ("Scrum Master",   GREEN,
         "移除阻碍 · 教 Agile 原则 · 保护 dev 免受 PO 越权",
         "product-lead （合并入 PO）",      CORAL,
         "AI agent 无人类利益冲突 · 无需独立 SM 政委",
         "✗ 合并"),
        ("Dev Team",        NAVY,
         "3-9 人 cross-functional · 自组织 / 自管理 · 对交付负责",
         "12 同事 dev team + tech-lead",    NAVY,
         "FE / BE / AI / ML / reviewer / qa · 高度自管理",
         "拆分"),
    ]
    row_h = 1.15
    row_top = 2.0
    for i, (sr, sc, sd, ar, ac, ad, mr) in enumerate(rows):
        y = Inches(row_top + i * row_h)
        # 左侧：Scrum 标准卡
        _add_card(s, Inches(0.55), y, Inches(4.95), Inches(1.0),
                  fill=WHITE, border=sc, accent=sc)
        _add_textbox(s, Inches(0.8), y + Inches(0.08), Inches(4.5), Inches(0.4),
                     sr, size_pt=15, bold=True, color=sc)
        _add_textbox(s, Inches(0.8), y + Inches(0.45), Inches(4.5), Inches(0.55),
                     sd, size_pt=10, color=GRAY_700)
        # 中间：合并理由 chip
        chip_color = CORAL if "合并" in mr else (GOLD if "拆分" in mr else GREEN)
        _add_card(s, Inches(5.6), y + Inches(0.2), Inches(1.4), Inches(0.6),
                  fill=chip_color, border=chip_color)
        _add_textbox(s, Inches(5.6), y + Inches(0.2), Inches(1.4), Inches(0.6),
                     mr, size_pt=13, bold=True, color=WHITE,
                     align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
        # 右侧：AGF 实际卡
        _add_card(s, Inches(7.1), y, Inches(5.7), Inches(1.0),
                  fill=WHITE, border=ac, accent=ac)
        _add_textbox(s, Inches(7.35), y + Inches(0.08), Inches(5.25), Inches(0.4),
                     ar, size_pt=15, bold=True, color=ac)
        _add_textbox(s, Inches(7.35), y + Inches(0.45), Inches(5.25), Inches(0.55),
                     ad, size_pt=10, color=GRAY_700)

    # tech-lead 旁注（非 Scrum 标准角色，额外说明）
    _add_textbox(s, Inches(0.55), Inches(5.6), Inches(12.2), Inches(0.4),
                 "ℹ tech-lead 不在 Scrum 标准 3 角色内 · AGF 加入处理架构 / ADR / 技术顾问 · 不参与流程编排",
                 size_pt=11, color=GRAY_500, align=PP_ALIGN.CENTER)

    # 底部：为什么 AGF 敢合并 PO + SM
    _add_card(s, Inches(0.55), Inches(6.1), Inches(12.2), Inches(1.15),
              fill=CORAL_LIGHT, border=CORAL)
    _add_textbox(s, Inches(0.8), Inches(6.2), Inches(11.7), Inches(0.4),
                 "为什么 AGF 敢合并 PO + SM？",
                 size_pt=14, bold=True, color=CORAL)
    _add_textbox(s, Inches(0.8), Inches(6.6), Inches(11.7), Inches(0.4),
                 "① 传统 SM 存在原因：防止 PO 越权干预 dev（人类利益冲突）  "
                 "② AI agent 无利益冲突 → 不需要独立 SM 当「政委」",
                 size_pt=11, color=NAVY)
    _add_textbox(s, Inches(0.8), Inches(7.0), Inches(11.7), Inches(0.4),
                 "③ SM 的「教 Agile」职责 → hook + skill 强制路径替代（机制嵌入，不靠人讲）  "
                 "学术参考：AI Scrum Master 自动化研究（Springer 2024）",
                 size_pt=11, color=NAVY)
    return s


def build_slide_30_brainstorming(prs):
    """slide 30: PL brainstorming 澄清 · 嵌入 A14"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · 第 1 幕 · PL 调 brainstorming 澄清")
    _add_centered_image(s, "A14-brainstorming-loop.png")
    return s


def build_slide_31_pipeline(prs):
    """slide 31: 三步流水线架构 · 嵌入 A3 (复用 p11 同图，§3 deep dive)"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · 三步流水线架构（全豆包 2.0 栈）")
    _add_centered_image(s, "A3-postcard-pipeline.png", height_inch=4.8, top_inch=1.5)
    # 与 p11 区分：本页 deep dive，重点拆 PRD AC + 派单 schema + ml-engineer 选型
    _add_textbox(s, Inches(0.55), Inches(6.5), Inches(12.2), Inches(0.4),
                 "回顾 p11 三步流水线 overview · 本节深入拆 ① 派单 schema · "
                 "② AC 量化 · ③ ml-engineer 选型矩阵",
                 size_pt=12, color=GRAY_500, align=PP_ALIGN.CENTER, bold=True)
    return s


def build_slide_32_prd(prs):
    """slide 32: PL 写 PRD · 引用 00-prd.md 摘录"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · PL 写 PRD 10 节 · 5 条 AC")
    _add_textbox(s, Inches(0.55), Inches(1.5), Inches(12.2), Inches(0.5),
                 "docs/training/samples/postcard-feature/00-prd.md（摘录）",
                 size_pt=14, color=GRAY_500)
    acs = [
        ("AC1", "时延", "P95 ≤ 30s（5 道盲测）"),
        ("AC2", "Vision 准确率", "≥ 85%（5/5 主体命中）"),
        ("AC3", "文案相关性", "≥ 4/5（3 评委盲评）"),
        ("AC4", "风格色调 hash", "≥ 0.75（Seedream 出图 vs LLM 关键词）"),
        ("AC5", "单次 cost", "≤ ¥0.30（实测 ¥0.21，余量 ¥0.09）"),
    ]
    from build_main import rotate5
    for i, (code, dim, target) in enumerate(acs):
        y = Inches(2.2 + i * 0.95)
        c = rotate5(i)
        _add_card(s, Inches(0.55), y, Inches(12.2), Inches(0.85),
                  fill=WHITE, border=c, accent=c)
        _add_textbox(s, Inches(0.85), y + Inches(0.15), Inches(1.2), Inches(0.55),
                     code, size_pt=22, bold=True, color=c)
        _add_textbox(s, Inches(2.2), y + Inches(0.1), Inches(3.5), Inches(0.4),
                     dim, size_pt=17, bold=True, color=NAVY)
        _add_textbox(s, Inches(2.2), y + Inches(0.45), Inches(9.8), Inches(0.4),
                     target, size_pt=14, color=GRAY_700)
    return s


def build_slide_33_dispatch(prs):
    """slide 33: 派单 6 段 schema · 嵌入 D2 + 引用 02-dispatch.md"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · 派单 6 段 schema · PL → ai-agent-dev")
    _add_centered_image(s, "D2-dispatch-6-segments.png", height_inch=5.0)
    _add_textbox(s, Inches(0.55), Inches(6.7), Inches(12.2), Inches(0.4),
                 "完整派单 · 02-dispatch.md · hook validate-task-schema.sh 阻断缺段",
                 size_pt=12, color=GRAY_500, align=PP_ALIGN.CENTER)
    return s


def build_slide_34_prd_task_split(prs):
    """slide 34: PRD → Task 拆分铁律 · 嵌入 C5"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · PRD → Task 拆分铁律 · 按角色边界切")
    _add_centered_image(s, "C5-prd-task-split.png")
    return s


def build_slide_35_adr(prs):
    """slide 35: TL 出 ADR 模型选型 · 引用 01-adr-model-selection.md"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · TL 出 ADR · 模型选型（4 厂商 × 3 类型矩阵）")
    _add_textbox(s, Inches(0.55), Inches(1.5), Inches(12.2), Inches(0.5),
                 "docs/training/samples/postcard-feature/01-adr-model-selection.md",
                 size_pt=14, color=GRAY_500)
    # 决策结论卡片
    _add_card(s, Inches(0.55), Inches(2.2), Inches(12.2), Inches(1.4),
              fill=CORAL_LIGHT, border=CORAL, accent=CORAL)
    _add_textbox(s, Inches(0.85), Inches(2.35), Inches(11.6), Inches(0.5),
                 "✓ 决策：全豆包 2.0 栈（Doubao-Seed-2.0-Pro + Doubao-Seedream-4.5）",
                 size_pt=20, bold=True, color=CORAL)
    _add_textbox(s, Inches(0.85), Inches(2.85), Inches(11.6), Inches(0.7),
                 "理由：架构最简（同账户 3 调用）· 成本最低（¥0.21 < AC5 ¥0.30）· latency 最低（同区域 + 原生多模态）",
                 size_pt=14, color=GRAY_700)
    # 4 选项简表
    _add_textbox(s, Inches(0.55), Inches(3.9), Inches(12.2), Inches(0.5),
                 "🔍 横向对比（详见 ADR §Options）：",
                 size_pt=16, bold=True, color=NAVY)
    options = [
        ("DeepSeek",  "仅文本 V4-Pro $0.14/$0.28",              "无 Vision / 无文生图，淘汰"),
        ("Doubao ✓",  "Seed-2.0-Pro + Seedream-4.5 · ¥0.21/张", "全栈同厂商，架构最简，选这个"),
        ("Qwen",      "Qwen3.6-VL + Max + Tongyi-Wanxiang",       "全栈但跨调用 latency 不可控"),
        ("MiniMax",   "abab7-VL + M2.7",                          "无文生图，淘汰"),
    ]
    for i, (vendor, model, verdict) in enumerate(options):
        y = Inches(4.55 + i * 0.55)
        color = CORAL if "✓" in vendor else GRAY_500
        _add_textbox(s, Inches(0.85), y, Inches(2.0), Inches(0.4),
                     vendor, size_pt=14, bold=True, color=color)
        _add_textbox(s, Inches(3.0), y, Inches(5.0), Inches(0.4),
                     model, size_pt=12, color=GRAY_700)
        _add_textbox(s, Inches(8.2), y, Inches(4.5), Inches(0.4),
                     verdict, size_pt=12, color=GRAY_700)
    return s


def build_slide_36_worktree_parallel(prs):
    """slide 36: dev 并行 worktree 强制 · 嵌入 A9 (复用 p35 同图，§3 实战用法)"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · dev 并行：worktree 强制 · 3 同事独立目录")
    _add_centered_image(s, "A9-worktree-parallel.png", height_inch=4.8, top_inch=1.5)
    # 与 p35 区分：p35 是教学概念（§2 Git 入门），本页是 §3 派单后的实战
    _add_textbox(s, Inches(0.55), Inches(6.5), Inches(12.2), Inches(0.4),
                 "回顾 p35 worktree 教学概念 · 本节落地：PRD 拆 4 Task 后，"
                 "PL 必走 worktree add 让 3 dev 并行不冲突",
                 size_pt=12, color=GRAY_500, align=PP_ALIGN.CENTER, bold=True)
    return s


def build_slide_37_prompt_is_code(prs):
    """slide 37: ai-agent-dev 独门 · prompt 是代码"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · ai-agent-dev 独门 · prompt 是代码")
    _add_textbox(s, Inches(0.55), Inches(1.6), Inches(12.2), Inches(0.6),
                 "prompt 用 markdown 文件管理（不 hardcode 进 Python）",
                 size_pt=20, bold=True, color=CORAL, align=PP_ALIGN.CENTER)
    items = [
        ("文件结构", "backend/app/agents/postcard_prompts/v1_*.md（3 文件：vision / llm / imagegen）"),
        ("🔄 改 prompt", "走 PR review · reviewer 看 prompt diff（content 变更而非 code 变更）"),
        ("版本化", "v1 / v2 / v1.1 共存目录 · A/B 实验对比"),
        ("🧪 评测", "prompt 改动 → 跑 5 道盲测题 → 看 AC3 文案相关性是否回归"),
        ("Plan Mode", "重构 prompt（如三步合二步）必先进 Plan Mode 拿 PL 授权"),
    ]
    from build_main import rotate5
    for i, (head, body) in enumerate(items):
        y = Inches(2.6 + i * 0.85)
        c = rotate5(i)
        _add_card(s, Inches(0.55), y, Inches(12.2), Inches(0.75),
                  fill=WHITE, border=c, accent=c)
        _add_textbox(s, Inches(0.85), y + Inches(0.1), Inches(2.8), Inches(0.55),
                     head, size_pt=16, bold=True, color=c)
        _add_textbox(s, Inches(3.8), y + Inches(0.18), Inches(8.8), Inches(0.45),
                     body, size_pt=13, color=GRAY_700)
    return s


def build_slide_38_ml_matrix(prs):
    """slide 38: ml-engineer 模型矩阵 · 嵌入 C2"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · ml-engineer · 4 厂商选型矩阵 + 豆包 fallback")
    _add_centered_image(s, "C2-llm-matrix.png")
    return s


def build_slide_39_progress(prs):
    """slide 39: progress 真实条目 · 引用 03-progress.md"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · progress/<role>.md 真实条目（ai-agent-dev）")
    _add_textbox(s, Inches(0.55), Inches(1.5), Inches(12.2), Inches(0.4),
                 "docs/training/samples/postcard-feature/03-progress.md（摘录）",
                 size_pt=12, color=GRAY_500)
    # 模拟 markdown 渲染（v0.3: 深底 GRAY_700 → 白字对比度提升）
    _add_card(s, Inches(0.55), Inches(2.0), Inches(12.2), Inches(4.8),
              fill=GRAY_700, border=GRAY_700)
    progress_text = (
        "# ai-agent-dev · 旅游明信片三步链路实现\n\n"
        "## AC 自验逐条 ✓\n"
        "| AC | 目标 | 实测 | 状态 |\n"
        "|---|---|---|---|\n"
        "| AC1 | P95 ≤ 30s | 27.4s | |\n"
        "| AC2 | Vision 准确率 ≥ 85% | 92%（5/5）| |\n"
        "| AC3 | 文案相关性 ≥ 4/5 | 4.3 / 5 | |\n"
        "| AC4 | 风格色调 hash ≥ 0.75 | 0.81 平均 | |\n"
        "| AC5 | cost ≤ ¥0.30 / 张 | ¥0.21 / 张实测 | |\n\n"
        "## SIT 证据（dev 自跑，code-reviewer audit）\n"
        "5/5 链路完整 · 平均 24.8s · 平均 ¥0.214\n"
        "详见 tests/sit/sit-log-2026-05-17.txt"
    )
    _add_textbox(s, Inches(0.85), Inches(2.1), Inches(11.6), Inches(4.6),
                 progress_text, size_pt=13, color=WHITE)
    _add_textbox(s, Inches(0.55), Inches(6.9), Inches(12.2), Inches(0.3),
                 "progress/<role>.md 是 self-reporting · UAT 签字后由 PL 归档到 docs/qa/<feature>-process-log.md",
                 size_pt=11, color=GRAY_500, align=PP_ALIGN.CENTER)
    return s


def build_slide_40_sit(prs):
    """slide 40: dev 自跑 SIT · 自画 checklist"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · dev 自跑 SIT + 证据落 progress")
    _add_textbox(s, Inches(0.55), Inches(1.5), Inches(12.2), Inches(0.5),
                 "🔍 SIT 4 项审计（agf-running-sit-tests skill）：",
                 size_pt=18, bold=True, color=NAVY)
    items = [
        ("① 链路完整性", "5 道盲测题走完三步链路 · 每步输入输出可追溯"),
        ("② AC 覆盖",     "5 条 AC 全部跑通 · 实测数据贴 progress"),
        ("③ 证据真实",     "stdout 含时间戳 · 输出文件 SHA256 · 不能口述"),
        ("④ 反例边界",     "3 类异常（违禁内容 / 大文件 / 纯文字图）必跑"),
    ]
    for i, (head, body) in enumerate(items):
        y = Inches(2.3 + i * 0.95)
        _add_card(s, Inches(0.55), y, Inches(12.2), Inches(0.85),
                  fill=WHITE, border=GREEN, accent=GREEN)
        _add_textbox(s, Inches(0.85), y + Inches(0.15), Inches(3.0), Inches(0.55),
                     head, size_pt=18, bold=True, color=GREEN)
        _add_textbox(s, Inches(4.0), y + Inches(0.2), Inches(8.5), Inches(0.5),
                     body, size_pt=14, color=GRAY_700)
    _add_textbox(s, Inches(0.55), Inches(6.5), Inches(12.2), Inches(0.5),
                 "SIT 缺证据比代码烂更严重 · code-reviewer 在 review 时 audit · 缺则 Request Changes",
                 size_pt=14, color=CORAL, align=PP_ALIGN.CENTER, bold=True)
    return s


def build_slide_41_three_metrics(prs):
    """slide 41: 多模态评测三指标 · 嵌入 F1 雷达"""
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§3 · 多模态输出三指标 · 三角雷达")
    _add_centered_image(s, "F1-multimodal-radar.png")
    return s


def build(prs):
    """构建 §2 14 张内容 slide (slide 28-41)"""
    build_slide_28_14_teammates(prs)
    build_slide_29_scrum_roles(prs)
    build_slide_30_brainstorming(prs)
    build_slide_31_pipeline(prs)
    build_slide_32_prd(prs)
    build_slide_33_dispatch(prs)
    build_slide_34_prd_task_split(prs)
    build_slide_35_adr(prs)
    build_slide_36_worktree_parallel(prs)
    build_slide_37_prompt_is_code(prs)
    build_slide_38_ml_matrix(prs)
    build_slide_39_progress(prs)
    build_slide_40_sit(prs)
    build_slide_41_three_metrics(prs)
