from pathlib import Path
import sys

from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_CELL_VERTICAL_ALIGNMENT
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Cm, Inches, Pt, RGBColor


def set_cell_shading(cell, fill):
    tc_pr = cell._tc.get_or_add_tcPr()
    shd = tc_pr.find(qn("w:shd"))
    if shd is None:
        shd = OxmlElement("w:shd")
        tc_pr.append(shd)
    shd.set(qn("w:fill"), fill)


def set_cell_margins(cell, top=100, start=120, bottom=100, end=120):
    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 edge, value in (("top", top), ("start", start), ("bottom", bottom), ("end", end)):
        tag = "w:" + edge
        node = tc_mar.find(qn(tag))
        if node is None:
            node = OxmlElement(tag)
            tc_mar.append(node)
        node.set(qn("w:w"), str(value))
        node.set(qn("w:type"), "dxa")


def set_repeat_table_header(row):
    tr_pr = row._tr.get_or_add_trPr()
    tbl_header = OxmlElement("w:tblHeader")
    tbl_header.set(qn("w:val"), "true")
    tr_pr.append(tbl_header)


def ensure_bullet_numbering(document):
    numbering = document.part.numbering_part.element
    abstract_ids = [
        int(node.get(qn("w:abstractNumId")))
        for node in numbering.findall(qn("w:abstractNum"))
    ]
    num_ids = [
        int(node.get(qn("w:numId")))
        for node in numbering.findall(qn("w:num"))
    ]
    abstract_id = max(abstract_ids or [0]) + 1
    num_id = max(num_ids or [0]) + 1

    abstract = OxmlElement("w:abstractNum")
    abstract.set(qn("w:abstractNumId"), str(abstract_id))
    multi_level = OxmlElement("w:multiLevelType")
    multi_level.set(qn("w:val"), "singleLevel")
    abstract.append(multi_level)
    level = OxmlElement("w:lvl")
    level.set(qn("w:ilvl"), "0")
    start = OxmlElement("w:start")
    start.set(qn("w:val"), "1")
    level.append(start)
    num_fmt = OxmlElement("w:numFmt")
    num_fmt.set(qn("w:val"), "bullet")
    level.append(num_fmt)
    level_text = OxmlElement("w:lvlText")
    level_text.set(qn("w:val"), "•")
    level.append(level_text)
    p_pr = OxmlElement("w:pPr")
    tabs = OxmlElement("w:tabs")
    tab = OxmlElement("w:tab")
    tab.set(qn("w:val"), "num")
    tab.set(qn("w:pos"), "600")
    tabs.append(tab)
    p_pr.append(tabs)
    indent = OxmlElement("w:ind")
    indent.set(qn("w:left"), "600")
    indent.set(qn("w:hanging"), "300")
    p_pr.append(indent)
    level.append(p_pr)
    abstract.append(level)
    numbering.append(abstract)

    num = OxmlElement("w:num")
    num.set(qn("w:numId"), str(num_id))
    abstract_ref = OxmlElement("w:abstractNumId")
    abstract_ref.set(qn("w:val"), str(abstract_id))
    num.append(abstract_ref)
    numbering.append(num)
    return num_id


def add_bullet(document, text):
    if not hasattr(document, "_task_bullet_num_id"):
        document._task_bullet_num_id = ensure_bullet_numbering(document)
    paragraph = document.add_paragraph(style="List Paragraph")
    num_pr = paragraph._p.get_or_add_pPr().get_or_add_numPr()
    ilvl = OxmlElement("w:ilvl")
    ilvl.set(qn("w:val"), "0")
    num_id = OxmlElement("w:numId")
    num_id.set(qn("w:val"), str(document._task_bullet_num_id))
    num_pr.append(ilvl)
    num_pr.append(num_id)
    paragraph.add_run(text)
    return paragraph


def add_step(document, number, title, text):
    paragraph = document.add_paragraph()
    paragraph.paragraph_format.space_before = Pt(8)
    paragraph.paragraph_format.space_after = Pt(3)
    run = paragraph.add_run(f"{number}. {title}")
    run.bold = True
    run.font.color.rgb = RGBColor(36, 99, 199)
    run.font.size = Pt(13)
    body = document.add_paragraph(text)
    body.paragraph_format.left_indent = Cm(0.65)
    body.paragraph_format.space_after = Pt(5)


def add_picture(document, path, caption):
    paragraph = document.add_paragraph()
    paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
    paragraph.paragraph_format.keep_with_next = True
    paragraph.add_run().add_picture(str(path), width=Inches(5.7))
    caption_p = document.add_paragraph()
    caption_p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    caption_p.paragraph_format.space_after = Pt(8)
    caption_run = caption_p.add_run(caption)
    caption_run.italic = True
    caption_run.font.size = Pt(9)
    caption_run.font.color.rgb = RGBColor(99, 115, 135)


def main():
    if len(sys.argv) != 3:
        raise SystemExit("usage: build_manual_docx.py working.docx output.docx")
    source = Path(sys.argv[1])
    output = Path(sys.argv[2])
    screenshots = Path(__file__).resolve().parent / "screenshots"
    document = Document(str(source))

    normal = document.styles["Normal"]
    normal.font.name = "宋体"
    normal._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
    normal.font.size = Pt(10.5)
    normal.paragraph_format.line_spacing = 1.35
    normal.paragraph_format.space_after = Pt(5)

    for style_name, size, color in (
        ("Heading 1", 16, RGBColor(31, 78, 121)),
        ("Heading 2", 13, RGBColor(36, 99, 199)),
        ("Heading 3", 11.5, RGBColor(52, 73, 101)),
    ):
        style = document.styles[style_name]
        style.font.name = "微软雅黑"
        style._element.rPr.rFonts.set(qn("w:eastAsia"), "微软雅黑")
        style.font.size = Pt(size)
        style.font.color.rgb = color
        style.font.bold = True
        style.paragraph_format.space_before = Pt(10)
        style.paragraph_format.space_after = Pt(5)
        style.paragraph_format.keep_with_next = True

    title = document.add_paragraph()
    title.alignment = WD_ALIGN_PARAGRAPH.CENTER
    title.paragraph_format.space_before = Pt(18)
    title.paragraph_format.space_after = Pt(6)
    run = title.add_run("AI 助手制定菜谱")
    run.bold = True
    run.font.name = "微软雅黑"
    run._element.rPr.rFonts.set(qn("w:eastAsia"), "微软雅黑")
    run.font.size = Pt(22)
    run.font.color.rgb = RGBColor(31, 78, 121)

    subtitle = document.add_paragraph()
    subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
    subtitle.paragraph_format.space_after = Pt(16)
    sub_run = subtitle.add_run("PC 端智慧食堂助手操作说明 · VWCG-1232 · 2026-08-18")
    sub_run.font.size = Pt(10)
    sub_run.font.color.rgb = RGBColor(107, 119, 135)

    callout = document.add_table(rows=1, cols=1)
    callout.autofit = False
    callout.columns[0].width = Cm(14.6)
    cell = callout.cell(0, 0)
    set_cell_shading(cell, "EEF5FF")
    set_cell_margins(cell, 140, 180, 140, 180)
    callout_p = cell.paragraphs[0]
    callout_p.paragraph_format.space_after = Pt(0)
    callout_run = callout_p.add_run(
        "本功能像直接询问豆包一样，根据用户明确写出的日期范围、地域、菜系和餐次生成菜谱草案；"
        "未命中后台业务工具的建议和说明类问题也会由豆包自然回答。"
    )
    callout_run.bold = True
    callout_run.font.color.rgb = RGBColor(36, 86, 145)

    document.add_heading("1. 适用对象与入口", level=1)
    add_bullet(document, "适用对象：PC 后台食堂管理员、营养人员、运营人员。")
    add_bullet(document, "悬浮入口：登录 PC 后台后，点击右下角“智慧食堂助手”。")
    add_bullet(document, "独立页面：进入 AI 助手页面，在底部输入问题。")
    add_bullet(document, "权限：沿用 AI 助手现有登录边界，不新增菜单和角色权限。")

    document.add_heading("2. 操作步骤", level=1)
    add_step(document, 1, "打开助手", "点击右下角机器人按钮，打开智慧食堂助手面板。")
    add_step(
        document,
        2,
        "输入菜谱需求",
        "输入“制定今日菜谱”可获得今天三餐；输入“给我生成重庆的菜谱”时，助手会保留重庆条件，再询问今天、明天还是一周。",
    )
    add_step(
        document,
        3,
        "查看七天结果",
        "结果按周一至周日分卡片展示，每餐区分主食、优质蛋白、蔬菜和汤饮/水果/奶豆类搭配。",
    )
    add_step(
        document,
        4,
        "询问运营建议",
        "输入“食堂夏季如何减少排队？请给三条具体建议”等问题，助手会直接自然回答，不会误跳餐厅设置或显示无关入口卡片。",
    )

    add_picture(
        document,
        screenshots / "context-preserved-clarification.png",
        "图 1  菜谱追问保留重庆地区条件",
    )

    add_picture(
        document,
        screenshots / "implemented-compact-single-day.png",
        "图 2  重庆地区单日三餐紧凑卡片",
    )

    document.add_page_break()
    document.add_heading("3. 常用问法", level=1)
    table = document.add_table(rows=1, cols=2)
    table.style = "Table Grid"
    table.autofit = False
    table.columns[0].width = Cm(7.0)
    table.columns[1].width = Cm(7.6)
    header = table.rows[0]
    set_repeat_table_header(header)
    for index, text in enumerate(("用户问法", "助手行为")):
        cell = header.cells[index]
        set_cell_shading(cell, "DCEBFA")
        set_cell_margins(cell)
        cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
        cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
        cell.paragraphs[0].add_run(text).bold = True
    rows = [
        ("制定今日菜谱", "生成今天早餐、午餐、晚餐；不查询项目菜品。"),
        ("生成杭州市今日晚餐菜谱", "按杭州常见口味生成今天晚餐，不依赖固定地域列表。"),
        ("帮我制定菜谱", "询问今天、明天还是一周，并提供三个快捷选项。"),
        ("给我生成重庆的菜谱", "保留重庆地区条件，再询问今天、明天还是一周。"),
        ("给我生成一周菜谱", "通用中式周一至周日早餐、午餐、晚餐；不猜地域。"),
        ("生成一份四川地区的一周午餐菜谱", "只生成 7 天午餐，体现四川常见口味并兼顾清淡变化。"),
        ("生成一份广东地区的一周午餐菜谱", "只生成 7 天午餐，体现蒸、白灼、炖汤等广东特点。"),
        ("河北地区的一周午餐食谱", "无“生成”二字也可识别为明确的地域周食谱需求。"),
        ("重庆一日食谱", "生成重庆地域的单日三餐，不要求固定的生成动词。"),
        ("食堂夏季如何减少排队", "由豆包直接回答运营建议，不跳转餐厅设置。"),
        ("今天一楼智慧餐厅晚餐有什么菜", "查询系统实际每日菜单，不进入生成链路。"),
        ("菜品库里有鱼香肉丝吗", "精确查询菜品库并直接回答有/没有，同时提供筛选入口。"),
    ]
    for question, behavior in rows:
        row = table.add_row()
        for index, value in enumerate((question, behavior)):
            cell = row.cells[index]
            set_cell_margins(cell)
            cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
            cell.paragraphs[0].add_run(value)

    add_picture(
        document,
        screenshots / "implemented-general-weekly-three-meals.png",
        "图 3  未指定地域时的通用中式一周三餐结果",
    )

    document.add_heading("4. 自然问答与可信边界", level=1)
    add_bullet(document, "餐饮知识、食堂运营建议、方案构思和说明类问题，可直接由豆包自然回答。")
    add_bullet(document, "模型成功回答时不显示“找功能入口、查人员信息、看不到入口”等通用澄清卡片。")
    add_bullet(document, "涉及真实人员、订单、金额、库存、权限、真实菜单或执行操作时，仍以系统工具和权限校验结果为准。")
    add_bullet(document, "聊天回答使用纯文本分点；没有可靠依据时不编造精确效果比例、统计数字或保证性结论。")

    document.add_heading("5. 复制与历史", level=1)
    add_bullet(document, "点击回答下方的复制按钮，可复制完整纯文本菜谱。")
    add_bullet(document, "点击助手顶部的历史按钮，可重新查看以前生成的周菜谱。")
    add_bullet(document, "悬浮助手和独立 AI 助手页都能恢复分日卡片。")

    document.add_heading("6. 注意事项", level=1)
    for text in (
        "菜谱是策划草案，使用前需结合实际供应、食材、人群和制作条件人工调整。",
        "不代表系统已有对应菜品，不代表已经上架或可以直接售卖。",
        "不计算成本、售价、份量、采购量和精确营养素。",
        "疾病、明确过敏或宗教禁忌属于高风险个体化需求，本期不生成医疗级处方。",
        "模型超时或结果不完整时，请稍后重试；系统不会改为查询项目菜品库。",
        "通用模型不能代替系统内真实数据查询或执行后台操作。",
    ):
        add_bullet(document, text)

    document.add_heading("7. 验证信息", level=1)
    info = document.add_paragraph()
    info.add_run("最后验证：").bold = True
    info.add_run("2026-08-18；本地 store PC 前端 Node.js 14，后端 PHP 7.3 容器。")
    info = document.add_paragraph()
    info.add_run("已验证：").bold = True
    info.add_run("重庆追问选择一周后保留地域、重庆一日食谱、今日三餐、杭州市晚餐、四川、广东、河北、通用中式一周、自然问答、权限边界、实际菜单查询回归与历史恢复。")

    output.parent.mkdir(parents=True, exist_ok=True)
    document.save(str(output))


if __name__ == "__main__":
    main()
