"""§5 场景 D · UAT + Release Retro · slide 70-79 (10 内容页) · v0.2 真实内容版

嵌入 4 张图（F3/A12/A16/A11）+ 6 张自画 + 引用 05-uat-report.md + 06-retro.md + 07-release-notes.md
"""

from pathlib import Path
from pptx.util import Inches
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_70_e2e(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · E2E · chrome-devtools-mcp + 真机抽测")
    _add_textbox(s, Inches(0.55), Inches(1.6), Inches(12.2), Inches(0.6),
                 "自动化 + 人工抽测两条腿走（仅自动 / 仅人工 都不够）",
                 size_pt=18, color=NAVY, align=PP_ALIGN.CENTER, bold=True)
    layers = [
        ("自动化", "chrome-devtools-mcp + Playwright · 跑 happy path + 关键回归",
                       "适合：UI 渲染、点击流、断言基础元素"),
        ("人工抽测", "5 道盲测题（业务方 + qa 各出）· 看'感觉对不对'",
                          "适合：AI 输出质量、文案风格、图像观感"),
    ]
    for i, (head, what, when) in enumerate(layers):
        y = Inches(2.7 + i * 1.6)
        color = BLUE_ACCENT if i == 0 else CORAL
        _add_card(s, Inches(0.55), y, Inches(12.2), Inches(1.5),
                  fill=WHITE, border=color, accent=color)
        _add_textbox(s, Inches(0.85), y + Inches(0.15), Inches(3.5), Inches(0.6),
                     head, size_pt=22, bold=True, color=color)
        _add_textbox(s, Inches(0.85), y + Inches(0.75), Inches(11.5), Inches(0.4),
                     what, size_pt=14, color=NAVY)
        _add_textbox(s, Inches(0.85), y + Inches(1.1), Inches(11.5), Inches(0.4),
                     when, size_pt=13, color=GRAY_700)
    # 中间锚点：两栏之间加大 "+" 符号
    _add_textbox(s, Inches(5.66), Inches(4.0), Inches(2.0), Inches(1.0),
                 "+", size_pt=72, bold=True, color=NAVY,
                 align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    return s


def build_slide_71_blind_test(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · 明信片 E2E · 5 道盲测命中率仪表盘（AC ≥ 80%）")
    _add_centered_image(s, "F3-blind-test-dashboard.png")
    return s


def build_slide_72_uat_vs_e2e(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · UAT · 业务 pass ≠ 技术 pass")
    _add_textbox(s, Inches(0.55), Inches(1.6), Inches(12.2), Inches(0.6),
                 "关键认知：业务方关心'分享出去会不会丢人'，不是 latency",
                 size_pt=18, color=CORAL, align=PP_ALIGN.CENTER, bold=True)
    # 左：E2E 关心
    _add_textbox(s, Inches(0.55), Inches(2.6), Inches(6.0), Inches(0.5),
                 "E2E（qa 视角）", size_pt=22, bold=True, color=BLUE_ACCENT)
    e2e_items = [
        "AC1 P95 latency ≤ 30s ?",
        "AC2 Vision 准确率 ≥ 85% ?",
        "AC5 cost ≤ ¥0.30 ?",
        "回归测试全过 ?",
        "API 200 OK ?",
    ]
    for i, item in enumerate(e2e_items):
        _add_textbox(s, Inches(0.85), Inches(3.2 + i * 0.5), Inches(5.8), Inches(0.4),
                     f"▎ {item}", size_pt=14, color=GRAY_700)
    # 右：UAT 关心
    _add_textbox(s, Inches(7.0), Inches(2.6), Inches(6.0), Inches(0.5),
                 "UAT（业务方视角）", size_pt=22, bold=True, color=CORAL)
    uat_items = [
        "文案能直接发朋友圈吗 ?",
        "图能看吗 / 风格喜欢吗 ?",
        "和我的旅游照匹配吗 ?",
        "朋友看了会觉得有意思吗 ?",
        "我会愿意再用一次吗 ?",
    ]
    for i, item in enumerate(uat_items):
        _add_textbox(s, Inches(7.3), Inches(3.2 + i * 0.5), Inches(5.8), Inches(0.4),
                     f"▎ {item}", size_pt=14, color=GRAY_700)
    return s


def build_slide_73_uat_report(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · UAT 报告样例 · 业务方 3 人签字")
    _add_textbox(s, Inches(0.55), Inches(1.5), Inches(12.2), Inches(0.4),
                 "docs/training/samples/postcard-feature/05-uat-report.md（摘录）",
                 size_pt=12, color=GRAY_500)
    # 5 道盲测结果摘录
    _add_textbox(s, Inches(0.55), Inches(2.0), Inches(12.2), Inches(0.4),
                 "5 道盲测结果（4/5 = 80% 达 AC 阈值）：",
                 size_pt=16, bold=True, color=NAVY)
    results = [
        ("题 1", "海边日落",     "", "Alice/Bob/Carol 全 ✓"),
        ("题 2", "山林晨雾",     "", "全 ✓"),
        ("题 3", "城市夜景",     "", "文案撞 cliché 模板（咖啡馆套话）→ P1 fail"),
        ("题 4", "古城街景",     "", "全 ✓"),
        ("题 5", "田园风光",     "", "全 ✓"),
    ]
    for i, (num, photo, status, note) in enumerate(results):
        y = Inches(2.6 + i * 0.55)
        color = GREEN if "" in status else CORAL
        _add_textbox(s, Inches(0.85), y, Inches(0.8), Inches(0.4),
                     num, size_pt=14, bold=True, color=NAVY)
        _add_textbox(s, Inches(1.8), y, Inches(2.5), Inches(0.4),
                     photo, size_pt=14, color=GRAY_700)
        _add_textbox(s, Inches(4.5), y, Inches(0.7), Inches(0.4),
                     status, size_pt=16, color=color)
        _add_textbox(s, Inches(5.4), y, Inches(7.4), Inches(0.4),
                     note, size_pt=13, color=GRAY_700)
    # 签字
    _add_card(s, Inches(0.55), Inches(5.5), Inches(12.2), Inches(1.5),
              fill=CORAL_LIGHT, border=CORAL, accent=CORAL)
    _add_textbox(s, Inches(0.85), Inches(5.65), Inches(11.6), Inches(0.5),
                 "✓ 综合 verdict · Pass（P0 全过 + P1 失败 1 个 cosmetic → issue #312 跟进 v1.1）",
                 size_pt=16, bold=True, color=CORAL)
    _add_textbox(s, Inches(0.85), Inches(6.15), Inches(11.6), Inches(0.8),
                 "签字：qa-engineer ✓ · product-lead ✓ · 业务方 3 人（Alice/Bob/Carol）✓",
                 size_pt=14, color=NAVY)
    return s


def build_slide_74_archive(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · 归档 · progress/ → docs/qa/")
    _add_centered_image(s, "A12-archive-progress.png")
    return s


def build_slide_75_release_tag(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · Release · MAJOR / MINOR 必打 tag（同会话内）")
    _add_textbox(s, Inches(0.55), Inches(1.5), Inches(12.2), Inches(0.5),
                 "真实 tag annotation 含 tagged-along commits：",
                 size_pt=16, bold=True, color=NAVY)
    _add_card(s, Inches(0.55), Inches(2.1), Inches(12.2), Inches(3.5),
              fill=GRAY_500, border=GRAY_500)
    cmd = ("git tag -a v1.0.0 -m \"Release v1.0.0 · 旅游明信片首版\n\n"
           "Tagged-along commits:\n"
           "- abc1234 feat: postcard three-step pipeline (PR #287)\n"
           "- def5678 feat: postcard API + DB schema (PR #288)\n"
           "- ghi9012 fix: PII redact in vision call log (PR #295)\n"
           "- jkl3456 fix: prompt-injection 防护 (PR #296)\"\n\n"
           "git push --tags\n"
           "gh release create v1.0.0 --notes-file CHANGELOG.md --latest")
    _add_textbox(s, Inches(0.85), Inches(2.25), Inches(11.6), Inches(3.2),
                 cmd, size_pt=13, color=WHITE)
    _add_textbox(s, Inches(0.55), Inches(5.9), Inches(12.2), Inches(0.5),
                 "tag-orphan 反模式：commit 后未同会话 git tag -a → PL 必须当次会话补打或解释延期",
                 size_pt=14, color=CORAL, align=PP_ALIGN.CENTER, bold=True)
    _add_textbox(s, Inches(0.55), Inches(6.5), Inches(12.2), Inches(0.4),
                 "完整 release notes · 07-release-notes.md（Keep a Changelog 6 节）",
                 size_pt=12, color=GRAY_500, align=PP_ALIGN.CENTER)
    return s


def build_slide_76_changelog(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · CHANGELOG.md 规范 + tag 反模式")
    _add_centered_image(s, "A16-release-changelog.png")
    return s


def build_slide_77_retro_7step(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · /agf-release-retro · 7 步流程（MAJOR/MINOR 强制）")
    _add_centered_image(s, "A11-release-retro-7step.png")
    return s


def build_slide_78_patch_skip(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · 为什么 PATCH 不做 retro")
    _add_textbox(s, Inches(0.55), Inches(1.7), Inches(12.2), Inches(0.7),
                 "取舍：避免'为复盘而复盘'",
                 size_pt=24, bold=True, color=CORAL, align=PP_ALIGN.CENTER)
    items = [
        ("PATCH 通常是什么", "1 个小 bug fix · typo 修复 · 文档校对"),
        ("做 retro 的成本", "全员 ~2h 协调 · PL 主持 · 文档 30 min"),
        ("能学到的", "几乎为零（PATCH 没多少'设计取舍'可复盘）"),
        ("更好的沉淀方式", "直接 commit message / PR description / issue 注释"),
        ("MAJOR/MINOR 才值得", "含新设计 / 新风险 / 跨多 PR 协调 → 真有 lesson learned"),
    ]
    from build_main import rotate5
    for i, (head, body) in enumerate(items):
        y = Inches(2.8 + 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(3.5), Inches(0.55),
                     head, size_pt=16, bold=True, color=c)
        _add_textbox(s, Inches(4.5), y + Inches(0.18), Inches(8.0), Inches(0.45),
                     body, size_pt=13, color=GRAY_700)
    return s


def build_slide_79_retro_sample(prs):
    s = prs.slides.add_slide(prs.slide_layouts[3])
    _title(s, "§6 · Retro 真实样例 · v1.0.0 明信片 feature")
    _add_textbox(s, Inches(0.55), Inches(1.5), Inches(12.2), Inches(0.4),
                 "docs/training/samples/postcard-feature/06-retro.md（脱敏摘录）",
                 size_pt=12, color=GRAY_500)
    # Keep + Improve
    _add_textbox(s, Inches(0.55), Inches(2.0), Inches(6.0), Inches(0.5),
                 "✓ Keep（有效做法 · 团队共识）", size_pt=18, bold=True, color=GREEN)
    keep_items = [
        "brainstorming 4 轮充分 → PRD 0 scope creep",
        "prompt 用 .md 文件管理 → 历史可追",
        "reviewer 双 verdict 一次性指出全部",
        "ml-engineer ADR 含 4 厂商矩阵",
    ]
    for i, item in enumerate(keep_items):
        _add_textbox(s, Inches(0.85), Inches(2.7 + i * 0.55), Inches(5.7), Inches(0.45),
                     f"▎ {item}", size_pt=12, color=GRAY_700)
    # Improve
    _add_textbox(s, Inches(7.0), Inches(2.0), Inches(6.0), Inches(0.5),
                 "Improve（Owner + Due 强制）", size_pt=18, bold=True, color=CORAL)
    improve_items = [
        ("I1 · pre-review checklist", "@ai-agent-dev · 2026-05-30"),
        ("I2 · UAT 异步化 (Notion 表)", "@product-lead · 2026-06-05"),
        ("I3 · brainstorming 多 1 轮 OK", "不改（账算得过）"),
        ("I4 · 文案 cliché 优化", "@ai-agent-dev · 2026-06-15"),
    ]
    for i, (head, owner) in enumerate(improve_items):
        y = Inches(2.7 + i * 0.7)
        _add_textbox(s, Inches(7.3), y, Inches(5.7), Inches(0.3),
                     head, size_pt=13, bold=True, color=NAVY)
        _add_textbox(s, Inches(7.3), y + Inches(0.32), Inches(5.7), Inches(0.3),
                     owner, size_pt=11, color=CORAL)
    _add_textbox(s, Inches(0.55), Inches(6.5), Inches(12.2), Inches(0.4),
                 "反例：以后加监控（无 Owner / 无 Due → 一定不会做）→ retro skill 阻断提交",
                 size_pt=12, color=GRAY_500, align=PP_ALIGN.CENTER)
    return s


def build(prs):
    """构建 §5 10 张内容 slide (slide 70-79)"""
    build_slide_70_e2e(prs)
    build_slide_71_blind_test(prs)
    build_slide_72_uat_vs_e2e(prs)
    build_slide_73_uat_report(prs)
    build_slide_74_archive(prs)
    build_slide_75_release_tag(prs)
    build_slide_76_changelog(prs)
    build_slide_77_retro_7step(prs)
    build_slide_78_patch_skip(prs)
    build_slide_79_retro_sample(prs)
