#!/usr/bin/env python3
from __future__ import annotations

import html
import re
import shutil
import subprocess
import tempfile
import zipfile
from pathlib import Path
from xml.etree import ElementTree as ET

ROOT = Path(__file__).resolve().parents[2]
WORK = Path(__file__).resolve().parent
OUTPUT = WORK / "output" / "YP-G1200食品安全检测仪简表.docx"
TEMPLATE = ROOT / "standards-stack/agent-skills/skills/kangbite-word-template/assets/kangbite-digital-sports-word-template.docx"
PREPARE = ROOT / "standards-stack/agent-skills/skills/kangbite-word-template/scripts/prepare_working_copy.py"

W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
ET.register_namespace("w", W)
ET.register_namespace("r", R)


def wtag(name: str) -> str:
    return f"{{{W}}}{name}"


def attrs(items: dict[str, str]) -> str:
    return " ".join(f'w:{key}="{value}"' for key, value in items.items())


def run(text: str, *, bold: bool = False, size: int = 21) -> str:
    rpr = (
        f"<w:rPr><w:rFonts w:ascii=\"Microsoft YaHei\" w:eastAsia=\"微软雅黑\" "
        f"w:hAnsi=\"Microsoft YaHei\"/><w:sz w:val=\"{size}\"/>"
        f"<w:szCs w:val=\"{size}\"/>"
        f"{'<w:b/><w:bCs/>' if bold else ''}</w:rPr>"
    )
    return f"<w:r>{rpr}<w:t>{html.escape(text)}</w:t></w:r>"


def paragraph(text: str, *, bold: bool = False, size: int = 21, align: str | None = None, before: int = 80, after: int = 80) -> ET.Element:
    jc = f"<w:jc w:val=\"{align}\"/>" if align else ""
    xml = (
        f"<w:p xmlns:w=\"{W}\"><w:pPr><w:spacing w:before=\"{before}\" w:after=\"{after}\"/>"
        f"{jc}</w:pPr>{run(text, bold=bold, size=size)}</w:p>"
    )
    return ET.fromstring(xml)


def heading(text: str, level: int = 1) -> ET.Element:
    size = 30 if level == 1 else 24
    before = 180 if level == 1 else 120
    xml = (
        f"<w:p xmlns:w=\"{W}\"><w:pPr><w:pStyle w:val=\"Heading{level}\"/>"
        f"<w:spacing w:before=\"{before}\" w:after=\"80\"/></w:pPr>"
        f"{run(text, bold=True, size=size)}</w:p>"
    )
    return ET.fromstring(xml)


def cell(text: str, width: int, *, shaded: bool = False, bold: bool = False) -> str:
    fill = "<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"F2F2F2\"/>" if shaded else ""
    return (
        f"<w:tc><w:tcPr><w:tcW w:w=\"{width}\" w:type=\"dxa\"/>"
        f"<w:tcMar><w:top w:w=\"80\" w:type=\"dxa\"/><w:left w:w=\"100\" w:type=\"dxa\"/>"
        f"<w:bottom w:w=\"80\" w:type=\"dxa\"/><w:right w:w=\"100\" w:type=\"dxa\"/></w:tcMar>"
        f"{fill}</w:tcPr><w:p><w:pPr><w:spacing w:after=\"40\"/></w:pPr>{run(text, bold=bold, size=18)}</w:p></w:tc>"
    )


def table(rows: list[list[str]], widths: list[int]) -> ET.Element:
    grid = "".join(f"<w:gridCol w:w=\"{width}\"/>" for width in widths)
    row_xml = []
    for idx, row in enumerate(rows):
        cells = "".join(cell(value, widths[col], shaded=idx == 0, bold=idx == 0 or col == 0) for col, value in enumerate(row))
        row_xml.append(f"<w:tr>{cells}</w:tr>")
    xml = (
        f"<w:tbl xmlns:w=\"{W}\"><w:tblPr><w:tblW w:w=\"8306\" w:type=\"dxa\"/>"
        f"<w:tblBorders><w:top w:val=\"single\" w:sz=\"4\" w:color=\"BFBFBF\"/>"
        f"<w:left w:val=\"single\" w:sz=\"4\" w:color=\"BFBFBF\"/>"
        f"<w:bottom w:val=\"single\" w:sz=\"4\" w:color=\"BFBFBF\"/>"
        f"<w:right w:val=\"single\" w:sz=\"4\" w:color=\"BFBFBF\"/>"
        f"<w:insideH w:val=\"single\" w:sz=\"4\" w:color=\"D9D9D9\"/>"
        f"<w:insideV w:val=\"single\" w:sz=\"4\" w:color=\"D9D9D9\"/></w:tblBorders>"
        f"<w:tblCellMar><w:top w:w=\"60\" w:type=\"dxa\"/><w:left w:w=\"80\" w:type=\"dxa\"/>"
        f"<w:bottom w:w=\"60\" w:type=\"dxa\"/><w:right w:w=\"80\" w:type=\"dxa\"/></w:tblCellMar>"
        f"</w:tblPr><w:tblGrid>{grid}</w:tblGrid>{''.join(row_xml)}</w:tbl>"
    )
    return ET.fromstring(xml)


def spacer() -> ET.Element:
    return ET.fromstring(f"<w:p xmlns:w=\"{W}\"><w:pPr><w:spacing w:after=\"70\"/></w:pPr></w:p>")


def replace_body(docx_path: Path) -> None:
    product_rows = [
        ["项目", "内容"],
        ["产品名称", "YP-G1200 多功能食品安全检测仪"],
        ["品牌", "优普云"],
        ["单价/数量/总价", "12000 元/台；1 台；合计 12000 元"],
        ["检测项目数量", "200 多项"],
        ["屏幕/系统", "7 英寸触摸屏；安卓智能操作系统"],
        ["检测通道/光源", "12 个通道；410、520、590、630 nm 四波长冷光源，最多可扩展 64 波长"],
        ["联网/数据", "WiFi、4G、GPRS、网线；结果上传平台、导出 Excel、U 盘拷贝；存储 20 万条"],
        ["供电", "交直流两用；直流 12V；可配 6Ah 锂电池"],
        ["打印", "内置热敏打印机，可打印检测报告和二维码"],
        ["尺寸/重量", "43 x 35 x 19 cm；主机净重 5.1 kg"],
    ]
    detect_rows = [
        ["检测类型", "典型项目"],
        ["食品添加剂", "二氧化硫、双氧水、亚硝酸盐、硝酸盐、苯甲酸钠、山梨酸、糖精钠、甜蜜素、安赛蜜、硫酸镁等"],
        ["有毒有害物质", "甲醛、吊白块、硼砂、过氧化苯甲酰、工业碱、溴酸钾、罗丹明 B、三聚氰胺、苏丹红等"],
        ["果蔬农药残留", "有机磷、氨基甲酸酯类；胶体金法可检测具体农药项目"],
        ["病害肉/肉品", "组胺、挥发性盐基氮、肉制品酸价、水发产品中组胺等"],
        ["重金属与食用油脂", "铅、镉、铬、汞、砷、锡、镍、铝；过氧化值、酸价、油脂丙二醛等"],
        ["瘦肉精/激素类兽药", "盐酸克伦特罗、沙丁胺醇、莱克多巴胺、己烯雌酚、喹乙醇等"],
        ["抗生素残留类兽药", "四环素类、硝基呋喃类、磺胺类、沙星类、喹诺酮类、庆大霉素、链霉素、阿莫西林、红霉素等"],
        ["水产品安全", "孔雀石绿、氯霉素、呋喃妥因/呋喃西林/呋喃它酮/呋喃唑酮代谢物等"],
        ["真菌毒素", "黄曲霉毒素 B1、黄曲霉毒素 M1、呕吐毒素、玉米赤霉烯酮、赭曲霉毒素 A 等"],
        ["水、酒、饮品", "乳品蛋白质；酒中甲醇、乙醇、杂醇油；蜂蜜糖类/淀粉酶/酸度；水中氰化物、余氯；饮料维 C 等"],
        ["调味品成分", "食醋总酸、酱油总酸、芝麻油纯度、谷氨酸钠、酱油氨基酸态氮、食盐中亚铁氰化钾、食盐中碘等"],
        ["食用色素", "胭脂红、苋菜红、赤藓红、诱惑红、柠檬黄、日落黄、亮蓝等"],
        ["动物疫病", "猪蓝耳、猪瘟、猪伪狂犬、猪口蹄疫相关抗体/蛋白、猪细小病毒、鸡禽流感等"],
    ]

    children = [
        paragraph("YP-G1200 多功能食品安全检测仪简表", bold=True, size=32, align="center", before=120, after=120),
        paragraph("按用户要求：只保留规格、价格和可检测类型，文字尽量简短。", size=19, align="center", before=0, after=120),
        heading("一、产品规格", 1),
        table(product_rows, [1700, 6606]),
        spacer(),
        heading("二、能检测哪些类型", 1),
        table(detect_rows, [2100, 6206]),
        spacer(),
        paragraph("说明：价格按用户最新表格口径整理；检测范围按附件 PDF 和用户给出的检测项归纳。", size=18),
        paragraph("来源：附件《YP-G1200 食品安全检测仪.pdf》；用户最新表格口径。", size=18),
    ]

    with tempfile.TemporaryDirectory(prefix="yp-g1200-docx-") as tmp_dir:
        tmp = Path(tmp_dir)
        with zipfile.ZipFile(docx_path) as archive:
            archive.extractall(tmp)

        document_path = tmp / "word/document.xml"
        tree = ET.parse(document_path)
        root = tree.getroot()
        body = root.find(wtag("body"))
        if body is None:
            raise RuntimeError("document.xml missing w:body")
        sect_pr = body.find(wtag("sectPr"))
        if sect_pr is None:
            raise RuntimeError("document.xml missing final w:sectPr")
        for child in list(body):
            if child is not sect_pr:
                body.remove(child)
        for item in reversed(children):
            body.insert(0, item)
        tree.write(document_path, encoding="UTF-8", xml_declaration=True)

        tmp_output = docx_path.with_suffix(".tmp.docx")
        with zipfile.ZipFile(tmp_output, "w", compression=zipfile.ZIP_DEFLATED) as archive:
            for path in sorted(tmp.rglob("*")):
                if path.is_file():
                    archive.write(path, path.relative_to(tmp).as_posix())
        shutil.move(tmp_output, docx_path)


def main() -> None:
    OUTPUT.parent.mkdir(parents=True, exist_ok=True)
    subprocess.run(["python3", str(PREPARE), str(TEMPLATE), str(OUTPUT)], check=True)
    replace_body(OUTPUT)
    print(OUTPUT)


if __name__ == "__main__":
    main()
