from __future__ import annotations

from pathlib import Path
from docx import Document
from docx.enum.section import WD_SECTION
from docx.enum.table import WD_ALIGN_VERTICAL
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Cm, Inches, Pt, RGBColor
from PIL import Image, ImageDraw, ImageFont


ROOT = Path(__file__).resolve().parent
OUT_DOCX = ROOT / "2026年5月月度总结与6月月度规划_管理层6页重写版.docx"
OUT_MD = ROOT / "monthly-summary-june-plan-6page-rewrite.md"
OUT_HTML = ROOT / "review.html"
OUT_SOURCE = ROOT / "source-index.csv"
DOWNLOAD_DOCX = Path("/Users/jack/Downloads/2026年5月月度总结与6月月度规划_管理层6页重写版.docx")
ELDERCARE_IMAGE = Path(
    "/Users/jack/code/010-cpt/008-zhct/zhctprompt/"
    "work/2026-05-23-ai-agent-3m-product-strategy-speech/"
    "assets/eldercare-four-capabilities-main-flow.svg.png"
)
ASSET_DIR = ROOT / "assets"
CLEAN_ELDERCARE_IMAGE = ASSET_DIR / "eldercare-four-capabilities-main-flow-clean.png"


TITLE = "2026年5月月度总结与6月月度规划"
SUBTITLE = "管理层6页重写版｜以交付周期压缩和产品化经营为主线"


SECTIONS = [
    {
        "title": "一、总结",
        "paras": [
            "5月的核心结论不是“做了多少项目”，而是智慧营养健康餐厅已经进入从项目制交付向产品化经营转型的阶段。金斯瑞、江西206、江苏国信、荣海小学、昌平教委、国庆一体机等项目暴露出同一类问题：客户要的不只是功能上线，而是结算、设备、食安、监管、现场环境和验收证据的完整闭环。",
            "因此，5月完成内容在本稿中不再逐项展开，而是压缩为三类可进入6月规划的资产：第一，企业、学校、教委、食安硬件等真实项目证据；第二，产品分层、售前intake、Q&A问题库、软著和手册视频等标准化资料；第三，AI Agent在市场机会、售前方案、产品设计、交付资产和经营复盘中的内部提效能力。",
        ],
        "tables": [
            {
                "headers": ["5月沉淀", "管理意义", "6月转化方向"],
                "rows": [
                    ["多项目交付推进", "证明需求真实，但也证明边开发边交付会拉长周期", "按轻量、中量、重量分层管理，避免所有项目都按重型项目推进"],
                    ["产品战略与项目资料", "已具备产品化底稿，缺少统一验收口径", "形成企业/机关标准包、学校/教委监管包、食安硬件包"],
                    ["Q&A问题库与纪要", "暴露服务器、网络、浏览器、硬件、数据源、证书等前置风险", "变成合同前检查清单和交付立项门禁"],
                    ["软著、手册视频、AI Agent", "从文档产出升级为交付资产和知识资产", "支撑销售材料、用户培训、验收证据和复盘效率"],
                ],
            }
        ],
    },
    {
        "title": "二、问题与偏差分析",
        "paras": [
            "本月最明确的问题是交付周期偏长。这个问题不能简单归因于研发效率，而要拆成项目经验、现场环境和协同边界三层原因。",
            "第一，我们此前没有完整做过这类软硬一体、现场环境复杂、客户组织多角色协同的项目，很多事项是在开发、联调、部署和客户使用中同时暴露，实际形成了边开发边交付的状态。第二，现场软硬件环境没有在签约和进场前被充分沟通，服务器、操作系统、浏览器版本、证书、网络访问、国产化适配、设备型号、视频流支持、第三方接口和硬件供应商责任边界等问题，在交付阶段才集中出现，团队被动响应。第三，甲方内部哪个部门、哪个人员负责服务器、网络、安全、财务、设备、供应商协调和验收，经常没有白纸黑字写清楚，导致问题出现后协调链条变长。",
            "这类偏差的管理价值在于：我们正在越来越有经验。后续交付不是等合同签完再补环境，而是在签约前就把现场环境、设备接口、责任人、验收口径和变更边界写入材料、报价、合同附件和项目启动清单。",
        ],
        "tables": [
            {
                "headers": ["根因", "典型表现", "6月纠偏动作"],
                "rows": [
                    ["项目类型新", "软件、硬件、现场、客户流程同步磨合", "建立项目分层和需求冻结，不把探索型内容当标准交付承诺"],
                    ["环境未前置", "服务器、国产化、浏览器、证书、内外网、视频流到现场才验证", "合同前输出现场环境确认表，未确认项不进入交付承诺"],
                    ["设备边界不清", "一体机、取餐柜、售卖柜、摄像头、称重台依赖厂家和现场联调", "设备型号、协议、SDK、固件、测试记录和售后责任进入白名单"],
                    ["甲方协同未固化", "网络、安全、财务、设备、供应商多部门协调慢", "逐项写清甲方部门、责任人、截止时间和替代方案"],
                    ["证据不标准", "问题、截图、手册、验收材料分散", "每个项目形成交付资产包：截图、视频、手册、Q&A、验收清单"],
                ],
            }
        ],
    },
    {
        "title": "三、规划总结",
        "paras": [
            "6月规划的总原则是：把5月完成内容转成可成交、可交付、可复用、可评审的产品资产。已完成工作不再单独作为成绩陈列，而是进入规划体系，成为产品包、交付门禁、销售素材和经营复盘的输入。",
            "面向月均300万元产品策略，6月不宜依赖少数复杂大项目硬推，而应形成“轻服务扩大覆盖、标准包快速成交、重型项目严格门禁、AI Agent提高复用效率”的组合打法。AI Agent对外不讲工具规则，而讲它如何让市场机会、售前方案、产品设计、交付资产和经营复盘更快进入闭环。",
        ],
        "subsections": [
            {
                "title": "3.1 产品组合：从单项目转为三类主线产品包",
                "table": {
                    "headers": ["产品包", "客户场景", "6月交付物"],
                    "rows": [
                        ["企业/机关标准包", "企事业单位、园区、国企食堂，重点解决报餐、结算、设备、报表和员工体验", "标准方案、报价边界、点位图、演示账号、项目案例和合同前检查清单"],
                        ["学校/教委监管包", "单校自主管理 + 教委监管闭环，覆盖食安、经费、营养、家校公示和整改督办", "学校端主流程、教委端数据字典、4类大屏、接口清单和样板学校试填"],
                        ["食安硬件证据链包", "留样、晨检、消毒、农残、视频巡查、取餐柜、称重台、一体机等软硬联动场景", "设备白名单、协议/SDK、异常处理、现场验收脚本和售后边界"],
                        ["营养健康场景包", "企业员工、学校学生、医院康养、养老机构、运动训练人群", "营养建议模板、养老四大能力图、主流程图和可演示的一页纸产品包"],
                    ],
                },
            },
            {
                "title": "3.2 项目分层：用复杂度控制交付周期",
                "table": {
                    "headers": ["层级", "定义", "管理动作"],
                    "rows": [
                        ["轻量级", "AI营养建议、电子菜单/价签、演示大屏、售前轻采集等低改造产品", "快速演示、快速报价、快速成交，不承诺复杂集成"],
                        ["中量级", "结算设备包、企业标准点位包、学校样板包，边界清晰但需要现场配置", "标准包 + 配置化交付，形成样板和手册"],
                        ["重量级", "金斯瑞、206、国信、区域教委等涉及多设备、多接口、多部门的项目", "合同前门禁、需求冻结、变更控制、交付成本和验收证据齐全后启动"],
                    ],
                },
            },
            {
                "title": "3.3 合同前置门禁：把交付风险写到白纸黑字",
                "table": {
                    "headers": ["门禁项", "必须确认内容", "输出形式"],
                    "rows": [
                        ["业务与验收", "主流程、异常流程、验收场景、上线范围、不可做事项", "需求冻结表、验收清单、变更规则"],
                        ["现场软件环境", "服务器归属与配置、操作系统、数据库、中间件、浏览器、证书、内外网、国产化适配", "现场环境确认表、风险备注、责任人"],
                        ["现场硬件环境", "设备型号、供应商、协议、SDK、固件、视频流、打印、扫码、称重、人脸识别", "设备白名单、联调记录、售后边界"],
                        ["数据与接口", "OA、支付、补贴、银行、财务对账、第三方平台、主数据来源", "接口清单、字段口径、测试账号、联调计划"],
                        ["甲方协同", "服务器、网络、安全、财务、设备、供应商、验收分别由哪个部门哪个人协调", "甲方责任矩阵、会议纪要、合同附件"],
                    ],
                },
            },
            {
                "title": "3.4 AI Agent与软著：从工具使用变成交付资产",
                "paras": [
                    "AI Agent在6月应进入团队生产链路，而不是作为单独展示点。市场机会Agent负责收集机会和竞品信号；售前方案Agent负责把客户场景变成标准包和报价边界；产品设计Agent负责输出角色、主流程、页面、数据对象和验收口径；交付资产Agent负责生成手册、视频、截图证据和Q&A；经营复盘Agent负责把项目状态、产品包复用、成本工时和收入机会汇总到月度看板。",
                    "软著工作也应纳入产品资产体系：已有产品按版本迭代申报，新硬件端和新场景包按独立产品重构材料，名称、功能、代码、架构和截图均避免与历史材料重复。它不是单纯合规材料，而是产品边界、功能说明、界面截图和交付证据的一次结构化整理。",
                ],
            },
            {
                "title": "3.5 6月四周节奏与验收",
                "table": {
                    "headers": ["时间", "重点动作", "验收口径"],
                    "rows": [
                        ["第1周", "完成合同前检查清单、现场环境确认表、设备白名单模板", "所有新项目进场前有责任人、环境、设备和验收边界"],
                        ["第2周", "企业/机关、学校/教委、食安硬件三类产品包成稿", "每类产品包有方案、报价边界、主流程和演示材料"],
                        ["第3周", "重点项目补交付资产包，Q&A问题进入知识库", "金斯瑞、206、国信、教委等项目有截图、手册、视频或验收证据"],
                        ["第4周", "经营复盘与7月路线图", "按产品包复盘收入机会、成本工时、复用次数、阻塞项和下月资源分配"],
                    ],
                },
            },
            {
                "title": "3.6 管理层需要拍板的事项",
                "table": {
                    "headers": ["事项", "建议决策", "未拍板风险"],
                    "rows": [
                        ["第一突破线", "优先把企业/机关标准包作为6月销售主线，学校/教委和食安硬件作为样板与增强包", "销售继续按客户临时需求分散推进，难以形成月均300万元的可复制路径"],
                        ["交付前置门禁", "合同、报价、项目启动前必须完成现场环境、设备接口、甲方责任矩阵和验收清单", "交付阶段继续被服务器、网络、硬件、国产化、第三方接口拖慢"],
                        ["重型项目审批", "金斯瑞、206、国信、区域教委等重型项目必须先冻结需求和变更规则，再承诺周期", "高客单项目吞噬标准产品资源，形成不可复制定制"],
                        ["经营数据责任", "销售、财务、交付共同补齐收入、回款、毛利、硬件成本、交付工时和复用次数", "只能看到销售额，看不到真实利润、现金流和复用能力"],
                    ],
                },
            },
            {
                "title": "3.7 三类产品包的主流程沉淀要求",
                "table": {
                    "headers": ["产品包", "必须沉淀的主流程", "6月最小可验收样张"],
                    "rows": [
                        ["企业/机关标准包", "员工订餐/支付、档口出餐、补贴结算、财务对账、经营看板", "一张主流程图、一套标准演示数据、一份报价边界"],
                        ["学校/教委监管包", "学校建档、日常台账、整改闭环、教委预警督办、家校公示", "单校能力地图、教委端4类大屏、问题闭环样例"],
                        ["食安硬件证据链包", "设备接入、现场采集、异常识别、人工复核、整改留痕、验收取证", "设备白名单、联调脚本、异常处理SOP"],
                    ],
                },
            },
        ],
        "paras_after": [
            "6月的管理验收不以“又做了多少功能”为核心，而以四个结果为核心：合同前风险是否前置，产品包是否能被销售复用，交付证据是否能被下一项目复用，经营数据是否能支撑月均300万元目标的资源配置判断。"
        ],
    },
]


def set_cell_shading(cell, fill: str) -> None:
    tc_pr = cell._tc.get_or_add_tcPr()
    shd = OxmlElement("w:shd")
    shd.set(qn("w:fill"), fill)
    tc_pr.append(shd)


def set_cell_margins(cell, top=80, start=80, bottom=80, end=80) -> None:
    tc = cell._tc
    tc_pr = tc.get_or_add_tcPr()
    tc_mar = tc_pr.first_child_found_in("w:tcMar")
    if tc_mar is None:
        tc_mar = OxmlElement("w:tcMar")
        tc_pr.append(tc_mar)
    for m, v in {"top": top, "start": start, "bottom": bottom, "end": end}.items():
        node = tc_mar.find(qn(f"w:{m}"))
        if node is None:
            node = OxmlElement(f"w:{m}")
            tc_mar.append(node)
        node.set(qn("w:w"), str(v))
        node.set(qn("w:type"), "dxa")


def set_table_width(table, widths_cm):
    for row in table.rows:
        for idx, width in enumerate(widths_cm):
            if idx < len(row.cells):
                row.cells[idx].width = Cm(width)


def style_table(table, widths_cm=None):
    table.style = "Table Grid"
    table.autofit = False
    if widths_cm:
        set_table_width(table, widths_cm)
    for r_idx, row in enumerate(table.rows):
        for cell in row.cells:
            cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
            set_cell_margins(cell, 70, 75, 70, 75)
            for p in cell.paragraphs:
                p.paragraph_format.space_after = Pt(0)
                p.paragraph_format.line_spacing = 1.0
                for run in p.runs:
                    run.font.name = "PingFang SC"
                    run._element.rPr.rFonts.set(qn("w:eastAsia"), "PingFang SC")
                    run.font.size = Pt(7.3)
            if r_idx == 0:
                set_cell_shading(cell, "D9EAF7")
                for p in cell.paragraphs:
                    for run in p.runs:
                        run.bold = True
                        run.font.color.rgb = RGBColor(17, 24, 39)
            else:
                set_cell_shading(cell, "FFFFFF")


def add_table(doc: Document, data: dict, widths_cm=None):
    rows = data["rows"]
    headers = data["headers"]
    table = doc.add_table(rows=1, cols=len(headers))
    for i, h in enumerate(headers):
        table.rows[0].cells[i].text = h
    for row in rows:
        cells = table.add_row().cells
        for i, value in enumerate(row):
            cells[i].text = value
    style_table(table, widths_cm)
    doc.add_paragraph()


def add_para(doc, text, style=None, bold_prefix=None):
    p = doc.add_paragraph(style=style)
    p.paragraph_format.space_after = Pt(3)
    p.paragraph_format.line_spacing = 1.05
    if bold_prefix and text.startswith(bold_prefix):
        r = p.add_run(bold_prefix)
        r.bold = True
        p.add_run(text[len(bold_prefix):])
    else:
        p.add_run(text)
    return p


def setup_doc() -> Document:
    doc = Document()
    section = doc.sections[0]
    section.page_width = Cm(21)
    section.page_height = Cm(29.7)
    section.top_margin = Cm(1.05)
    section.bottom_margin = Cm(1.0)
    section.left_margin = Cm(1.05)
    section.right_margin = Cm(1.05)

    styles = doc.styles
    normal = styles["Normal"]
    normal.font.name = "PingFang SC"
    normal._element.rPr.rFonts.set(qn("w:eastAsia"), "PingFang SC")
    normal.font.size = Pt(8.6)
    normal.paragraph_format.space_after = Pt(3)
    normal.paragraph_format.line_spacing = 1.05

    for name, size, color in [
        ("Heading 1", 13, "0F172A"),
        ("Heading 2", 10, "0F172A"),
        ("Heading 3", 9, "0F172A"),
    ]:
        s = styles[name]
        s.font.name = "PingFang SC"
        s._element.rPr.rFonts.set(qn("w:eastAsia"), "PingFang SC")
        s.font.size = Pt(size)
        s.font.bold = True
        s.font.color.rgb = RGBColor.from_string(color)
        s.paragraph_format.space_before = Pt(4)
        s.paragraph_format.space_after = Pt(3)

    return doc


def font(size: int, bold: bool = False):
    candidates = [
        "/System/Library/Fonts/PingFang.ttc",
        "/System/Library/Fonts/STHeiti Light.ttc",
        "/Library/Fonts/Arial Unicode.ttf",
    ]
    for path in candidates:
        if Path(path).exists():
            try:
                return ImageFont.truetype(path, size=size, index=1 if bold else 0)
            except Exception:
                try:
                    return ImageFont.truetype(path, size=size)
                except Exception:
                    pass
    return ImageFont.load_default()


def draw_wrapped(draw, xy, text, fnt, fill, max_width, line_gap=8):
    x, y = xy
    line = ""
    for ch in text:
        trial = line + ch
        if draw.textlength(trial, font=fnt) <= max_width:
            line = trial
        else:
            draw.text((x, y), line, font=fnt, fill=fill)
            y += fnt.size + line_gap
            line = ch
    if line:
        draw.text((x, y), line, font=fnt, fill=fill)
    return y + fnt.size


def rounded_card(draw, box, radius=28, fill="#ffffff", outline="#dbeafe"):
    draw.rounded_rectangle(box, radius=radius, fill=fill, outline=outline, width=2)


def build_clean_eldercare_image():
    ASSET_DIR.mkdir(parents=True, exist_ok=True)
    w, h = 1600, 900
    img = Image.new("RGB", (w, h), "#f6fbfb")
    draw = ImageDraw.Draw(img)
    title_f = font(52, True)
    sub_f = font(28)
    h_f = font(30, True)
    b_f = font(24)
    small_f = font(21)
    draw.text((80, 58), "养老场景四大能力与主流程", font=title_f, fill="#0f172a")
    draw.text((82, 132), "把营养健康、食安、结算和AI识别能力组合成可售场景包", font=sub_f, fill="#475569")

    cards = [
        ("1", "老年营养档案", "慢病标签、吞咽分级、饮食禁忌、营养风险"),
        ("2", "适老化食谱", "低盐低脂、易消化、餐次控量、周期菜单"),
        ("3", "摄入记录", "小碗菜识别、称重记录、订餐消费、连续饮食数据"),
        ("4", "照护协同", "异常提醒、家属/护理员协同、周月营养复盘"),
    ]
    card_w, card_h = 330, 190
    x0, y0, gap = 80, 225, 40
    for i, (num, head, body) in enumerate(cards):
        x = x0 + i * (card_w + gap)
        rounded_card(draw, (x, y0, x + card_w, y0 + card_h))
        draw.ellipse((x + 28, y0 + 42, x + 88, y0 + 102), fill="#0f766e")
        draw.text((x + 49, y0 + 55), num, font=h_f, fill="white", anchor="mm")
        draw.text((x + 108, y0 + 42), head, font=h_f, fill="#0f172a")
        draw_wrapped(draw, (x + 32, y0 + 112), body, b_f, "#475569", card_w - 64, 5)

    draw.text((80, 510), "主流程", font=h_f, fill="#0f172a")
    flow = [("建档评估", "人群分层"), ("生成食谱", "餐次计划"), ("采购备餐", "食安留痕"), ("供餐记录", "识别称重"), ("异常提醒", "照护协同"), ("周月复盘", "营养改善")]
    box_w, box_h = 205, 92
    fx, fy, fg = 80, 585, 42
    for i, (a, b) in enumerate(flow):
        x = fx + i * (box_w + fg)
        draw.rounded_rectangle((x, fy, x + box_w, fy + box_h), radius=18, fill="#ffffff", outline="#dbeafe", width=2)
        draw.text((x + box_w / 2, fy + 22), a, font=b_f, fill="#0f172a", anchor="mt")
        draw.text((x + box_w / 2, fy + 56), b, font=small_f, fill="#64748b", anchor="mt")
        if i < len(flow) - 1:
            ax = x + box_w + 9
            ay = fy + box_h / 2
            draw.line((ax, ay, ax + fg - 18, ay), fill="#0f766e", width=6)
            draw.polygon([(ax + fg - 18, ay - 13), (ax + fg + 8, ay), (ax + fg - 18, ay + 13)], fill="#0f766e")

    draw.rounded_rectangle((80, 760, 1520, 835), radius=22, fill="#0f766e")
    draw.text((112, 782), "对外表达：养老不是另起一套系统，而是把已有餐厅能力扩展为康养场景包。", font=small_f, fill="#ecfccb")
    img.save(CLEAN_ELDERCARE_IMAGE)


def build_docx():
    build_clean_eldercare_image()
    doc = setup_doc()

    title = doc.add_paragraph()
    title.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = title.add_run(TITLE)
    run.bold = True
    run.font.name = "PingFang SC"
    run._element.rPr.rFonts.set(qn("w:eastAsia"), "PingFang SC")
    run.font.size = Pt(18)
    run.font.color.rgb = RGBColor(15, 23, 42)

    subtitle = doc.add_paragraph()
    subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = subtitle.add_run(SUBTITLE)
    r.font.name = "PingFang SC"
    r._element.rPr.rFonts.set(qn("w:eastAsia"), "PingFang SC")
    r.font.size = Pt(9)
    r.font.color.rgb = RGBColor(71, 85, 105)
    subtitle.paragraph_format.space_after = Pt(8)

    callout = doc.add_paragraph()
    callout.paragraph_format.left_indent = Cm(0.2)
    callout.paragraph_format.right_indent = Cm(0.2)
    callout.paragraph_format.space_after = Pt(5)
    c = callout.add_run("核心口径：")
    c.bold = True
    callout.add_run("5月总结控制在30%左右，重点用于证明6月规划；6月规划占70%左右，围绕交付前置、产品分层、AI Agent提效和月均300万元经营目标展开。")

    for idx, section in enumerate(SECTIONS):
        if idx == 1:
            doc.add_section(WD_SECTION.CONTINUOUS)
        doc.add_heading(section["title"], level=1)
        for para in section.get("paras", []):
            add_para(doc, para)
        for table in section.get("tables", []):
            widths = [3.7, 6.7, 8.4] if len(table["headers"]) == 3 else None
            if len(table["headers"]) == 2:
                widths = [4.2, 14.5]
            add_table(doc, table, widths)
        for sub in section.get("subsections", []):
            doc.add_heading(sub["title"], level=2)
            for para in sub.get("paras", []):
                add_para(doc, para)
            if "table" in sub:
                cols = len(sub["table"]["headers"])
                if cols == 3:
                    widths = [3.1, 7.1, 8.6]
                else:
                    widths = [3.6, 5.2, 4.8, 5.2]
                add_table(doc, sub["table"], widths)
            if sub["title"].startswith("3.1") and CLEAN_ELDERCARE_IMAGE.exists():
                p = doc.add_paragraph()
                p.alignment = WD_ALIGN_PARAGRAPH.CENTER
                p.paragraph_format.space_after = Pt(2)
                p.add_run("图：养老场景四大能力与主流程（作为营养健康场景包储备素材）").italic = True
                doc.add_picture(str(CLEAN_ELDERCARE_IMAGE), width=Inches(4.55))
                doc.paragraphs[-1].alignment = WD_ALIGN_PARAGRAPH.CENTER
        for para in section.get("paras_after", []):
            add_para(doc, para)

    footer = doc.sections[0].footer.paragraphs[0]
    footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
    footer.text = "证据口径：项目资料、会议纪要和Q&A为内部管理证据；经营目标与产品优先级为6月待验证规划口径。"
    for run in footer.runs:
        run.font.size = Pt(7)
        run.font.color.rgb = RGBColor(100, 116, 139)

    doc.save(OUT_DOCX)
    DOWNLOAD_DOCX.write_bytes(OUT_DOCX.read_bytes())


def markdown_table(headers, rows):
    out = ["| " + " | ".join(headers) + " |", "| " + " | ".join(["---"] * len(headers)) + " |"]
    for row in rows:
        out.append("| " + " | ".join(row) + " |")
    return "\n".join(out)


def build_markdown():
    lines = [f"# {TITLE}", "", SUBTITLE, "", "> 核心口径：5月总结控制在30%左右，重点用于证明6月规划；6月规划占70%左右，围绕交付前置、产品分层、AI Agent提效和月均300万元经营目标展开。", ""]
    for sec in SECTIONS:
        lines.extend([f"## {sec['title']}", ""])
        for p in sec.get("paras", []):
            lines.extend([p, ""])
        for t in sec.get("tables", []):
            lines.extend([markdown_table(t["headers"], t["rows"]), ""])
        for sub in sec.get("subsections", []):
            lines.extend([f"### {sub['title']}", ""])
            for p in sub.get("paras", []):
                lines.extend([p, ""])
            if "table" in sub:
                lines.extend([markdown_table(sub["table"]["headers"], sub["table"]["rows"]), ""])
            if sub["title"].startswith("3.1"):
                lines.append("![养老场景四大能力与主流程](assets/eldercare-four-capabilities-main-flow-clean.png)")
                lines.append("")
        for p in sec.get("paras_after", []):
            lines.extend([p, ""])
    lines.extend(["## 来源与边界", "", "- 原始13页管理层版作为结构和事实底稿。", "- 三份会议纪要、Q&A快照和AI Agent演讲稿包作为补充证据。", "- 经营目标与产品优先级属于6月规划口径，需用收入、毛利、回款、交付工时和复用率继续验证。", ""])
    OUT_MD.write_text("\n".join(lines), encoding="utf-8")


def build_html():
    css = """
    body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',Arial,sans-serif;margin:0;color:#0f172a;background:#f8fafc;}
    main{max-width:980px;margin:0 auto;padding:36px 28px 56px;background:white;box-shadow:0 12px 40px rgba(15,23,42,.08);}
    h1{font-size:32px;margin:0 0 6px;} .sub{color:#475569;margin-bottom:22px;}
    .callout{background:#e0f2fe;border-left:5px solid #0284c7;padding:14px 16px;margin:18px 0;border-radius:6px;}
    h2{font-size:22px;margin-top:30px;border-bottom:1px solid #e2e8f0;padding-bottom:6px;} h3{font-size:17px;margin-top:22px;}
    p{line-height:1.75;font-size:15px;} table{border-collapse:collapse;width:100%;margin:12px 0 18px;font-size:13px;} th,td{border:1px solid #cbd5e1;padding:9px 10px;vertical-align:top;} th{background:#d9eaf7;text-align:left;} img{max-width:760px;width:100%;display:block;margin:12px auto;border:1px solid #e2e8f0;border-radius:8px;}
    """
    html = [f"<!doctype html><meta charset='utf-8'><title>{TITLE}</title><style>{css}</style><main>"]
    html.append(f"<h1>{TITLE}</h1><div class='sub'>{SUBTITLE}</div>")
    html.append("<div class='callout'><strong>核心口径：</strong>5月总结控制在30%左右，重点用于证明6月规划；6月规划占70%左右，围绕交付前置、产品分层、AI Agent提效和月均300万元经营目标展开。</div>")
    for sec in SECTIONS:
        html.append(f"<h2>{sec['title']}</h2>")
        for p in sec.get("paras", []):
            html.append(f"<p>{p}</p>")
        for t in sec.get("tables", []):
            html.append(to_html_table(t))
        for sub in sec.get("subsections", []):
            html.append(f"<h3>{sub['title']}</h3>")
            for p in sub.get("paras", []):
                html.append(f"<p>{p}</p>")
            if "table" in sub:
                html.append(to_html_table(sub["table"]))
            if sub["title"].startswith("3.1") and CLEAN_ELDERCARE_IMAGE.exists():
                rel = Path("assets/eldercare-four-capabilities-main-flow-clean.png")
                html.append(f"<img src='{rel}' alt='养老场景四大能力与主流程'>")
        for p in sec.get("paras_after", []):
            html.append(f"<p>{p}</p>")
    html.append("<h2>来源与边界</h2><p>原始13页管理层版作为结构和事实底稿；三份会议纪要、Q&A快照和AI Agent演讲稿包作为补充证据。经营目标与产品优先级属于6月规划口径，需用收入、毛利、回款、交付工时和复用率继续验证。</p>")
    html.append("</main>")
    OUT_HTML.write_text("\n".join(html), encoding="utf-8")


def to_html_table(t):
    out = ["<table><thead><tr>"]
    for h in t["headers"]:
        out.append(f"<th>{h}</th>")
    out.append("</tr></thead><tbody>")
    for row in t["rows"]:
        out.append("<tr>")
        for c in row:
            out.append(f"<td>{c}</td>")
        out.append("</tr>")
    out.append("</tbody></table>")
    return "".join(out)


def build_source_index():
    rows = [
        ["source_id", "path", "evidence_level", "usage"],
        ["SRC-01", "/Users/jack/Downloads/2026年5月月度总结与6月月度规划_管理层版.docx", "B", "原始13页管理层版，作为事实和结构底稿"],
        ["SRC-02", "/Users/jack/Downloads/纪要_软著申请策略与项目交付推进会.txt", "B", "软著、AI视频、设备选型、项目交付和二级等保环境风险"],
        ["SRC-03", "/Users/jack/Downloads/纪要_产品与项目进展同步会.txt", "B", "一体机、服务器、大屏视频、产品认证和交付阻塞"],
        ["SRC-04", "/Users/jack/Downloads/纪要_产品策略与项目交付周会纪要.txt", "B", "教委端/单校端、三级火箭、AI手册与项目经验产品化"],
        ["SRC-05", "work_company_knowledge/online-documents/2026-05-21-wedoc-problem-qa/", "B", "Q&A问题库，用于合同前置风险和现场环境门禁"],
        ["SRC-06", "work/2026-05-23-ai-agent-3m-product-strategy-speech/", "B/D", "AI Agent、月均300万、养老四大能力与主流程素材"],
    ]
    OUT_SOURCE.write_text("\n".join(",".join(row) for row in rows), encoding="utf-8")


if __name__ == "__main__":
    build_docx()
    build_markdown()
    build_html()
    build_source_index()
    print(OUT_DOCX)
    print(OUT_MD)
    print(OUT_HTML)
    print(OUT_SOURCE)
    print(DOWNLOAD_DOCX)
