from pathlib import Path
import re
from html import escape
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.section import WD_SECTION
from docx.enum.style import WD_STYLE_TYPE
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

ROOT = Path(__file__).resolve().parents[1]
MD = ROOT / "smart-menu-android-user-manual.md"
HTML = ROOT / "smart-menu-android-user-manual.html"
DOCX = ROOT / "智能排菜系统Android Pad客户端用户操作手册.docx"


def inline(text):
    text = escape(text)
    text = re.sub(r"`([^`]+)`", r"<code>\1</code>", text)
    text = re.sub(r"\*\*([^*]+)\*\*", r"<strong>\1</strong>", text)
    return text


def build_html(lines):
    body, in_ul, in_ol = [], False, False
    for raw in lines:
        line = raw.rstrip()
        if line.startswith("- "):
            if in_ol:
                body.append("</ol>"); in_ol = False
            if not in_ul:
                body.append("<ul>"); in_ul = True
            body.append(f"<li>{inline(line[2:])}</li>")
            continue
        m_num = re.match(r"^(\d+)\.\s+(.*)$", line)
        if m_num:
            if in_ul:
                body.append("</ul>"); in_ul = False
            if not in_ol:
                body.append("<ol>"); in_ol = True
            body.append(f"<li>{inline(m_num.group(2))}</li>")
            continue
        if in_ul:
            body.append("</ul>"); in_ul = False
        if in_ol:
            body.append("</ol>"); in_ol = False
        if not line:
            continue
        if line.startswith("# "):
            body.append(f"<h1>{inline(line[2:])}</h1>")
        elif line.startswith("## "):
            body.append(f"<h2>{inline(line[3:])}</h2>")
        elif line.startswith("### "):
            body.append(f"<h3>{inline(line[4:])}</h3>")
        elif line.startswith("> "):
            body.append(f"<aside>{inline(line[2:])}</aside>")
        elif re.match(r"^!\[.*\]\(.+\)$", line):
            m = re.match(r"^!\[(.*)\]\((.+)\)$", line)
            body.append(f'<figure><img src="{escape(m.group(2))}" alt="{escape(m.group(1))}"><figcaption>{escape(m.group(1))}</figcaption></figure>')
        else:
            body.append(f"<p>{inline(line.replace('  ', ' '))}</p>")
    if in_ul: body.append("</ul>")
    if in_ol: body.append("</ol>")
    css = """
    :root{--ink:#172033;--muted:#667085;--blue:#246BFD;--orange:#F46A2A;--line:#E4E9F2;--soft:#F5F8FC}
    *{box-sizing:border-box}body{margin:0;background:#edf1f6;color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;line-height:1.75}
    .hero{background:linear-gradient(135deg,#14213d,#246BFD);color:#fff;padding:54px 24px}.hero-inner,main{max-width:1080px;margin:auto}.hero h1{font-size:38px;margin:0 0 12px}.hero p{opacity:.86;margin:0}
    main{background:#fff;margin:28px auto 60px;padding:48px 66px;border-radius:20px;box-shadow:0 18px 55px rgba(23,32,51,.08)}
    main>h1{display:none}h2{font-size:25px;margin:46px 0 16px;padding-bottom:10px;border-bottom:2px solid #edf1f6}h3{font-size:19px;margin:30px 0 10px;color:#194ea8}
    p{margin:9px 0}ul,ol{padding-left:26px}li{margin:6px 0}strong{color:#101828}code{background:#eef4ff;padding:2px 6px;border-radius:5px}
    aside{margin:22px 0;padding:18px 20px;border-left:5px solid var(--orange);background:#fff7f1;border-radius:10px;color:#5c4032}
    figure{margin:24px 0 34px}figure img{display:block;width:100%;border:1px solid var(--line);border-radius:14px;box-shadow:0 10px 28px rgba(23,32,51,.1)}figcaption{text-align:center;color:var(--muted);font-size:14px;margin-top:9px}
    .meta{display:flex;gap:18px;flex-wrap:wrap;font-size:14px;opacity:.9}@media(max-width:700px){main{margin:0;padding:26px 20px;border-radius:0}.hero h1{font-size:30px}}
    @media print{body{background:#fff}.hero{padding:28px}main{box-shadow:none;margin:0;padding:30px}figure{break-inside:avoid}h2,h3{break-after:avoid}}
    """
    return f"""<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>智能排菜系统用户操作手册</title><style>{css}</style></head><body><header class="hero"><div class="hero-inner"><h1>智能排菜系统用户操作手册</h1><p>Android Pad 客户端 · 称重台排菜与档口菜谱维护</p><div class="meta"><span>版本 V1.0</span><span>核验日期 2026-07-14</span><span>适用：运营人员 / 店长 / 实施运维</span></div></div></header><main>{''.join(body)}</main></body></html>"""


def set_font(run, name="Arial Unicode MS", size=None, bold=None, color=None):
    run.font.name = name
    run._element.get_or_add_rPr().rFonts.set(qn("w:eastAsia"), name)
    run._element.rPr.rFonts.set(qn("w:ascii"), name)
    run._element.rPr.rFonts.set(qn("w:hAnsi"), name)
    run._element.rPr.rFonts.set(qn("w:cs"), name)
    run._element.rPr.rFonts.set(qn("w:hint"), "eastAsia")
    if size: run.font.size = Pt(size)
    if bold is not None: run.bold = bold
    if color: run.font.color.rgb = RGBColor(*color)


def add_page_number(paragraph):
    paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
    run = paragraph.add_run("第 ")
    fld = OxmlElement("w:fldSimple"); fld.set(qn("w:instr"), "PAGE")
    run._r.addnext(fld)
    paragraph.add_run(" 页")


def add_inline_runs(paragraph, text):
    for part in re.split(r"(\*\*.*?\*\*|`.*?`)", text):
        if part.startswith("**") and part.endswith("**"):
            set_font(paragraph.add_run(part[2:-2]), bold=True)
        elif part.startswith("`") and part.endswith("`"):
            set_font(paragraph.add_run(part[1:-1]), name="Menlo", size=9, color=(25, 78, 168))
        else:
            paragraph.add_run(part)


def restart_list_numbering(doc, paragraph):
    """Give a List Number paragraph a fresh real Word numbering sequence."""
    style_num_id = doc.styles["List Number"]._element.pPr.numPr.numId.val
    numbering = doc.part.numbering_part.element
    source_num = next(node for node in numbering.findall(qn("w:num")) if node.get(qn("w:numId")) == str(style_num_id))
    abstract_num_id = source_num.find(qn("w:abstractNumId")).get(qn("w:val"))
    existing = [int(node.get(qn("w:numId"))) for node in numbering.findall(qn("w:num"))]
    num_id = max(existing, default=0) + 1
    num = OxmlElement("w:num"); num.set(qn("w:numId"), str(num_id))
    abstract = OxmlElement("w:abstractNumId"); abstract.set(qn("w:val"), abstract_num_id); num.append(abstract)
    override = OxmlElement("w:lvlOverride"); override.set(qn("w:ilvl"), "0")
    start = OxmlElement("w:startOverride"); start.set(qn("w:val"), "1"); override.append(start); num.append(override)
    numbering.append(num)
    paragraph._p.get_or_add_pPr().get_or_add_numPr().get_or_add_numId().val = num_id
    return num_id


def build_docx(lines):
    doc = Document()
    sec = doc.sections[0]
    sec.page_width, sec.page_height = Inches(8.5), Inches(11)
    sec.top_margin = sec.bottom_margin = sec.left_margin = sec.right_margin = Inches(1)
    sec.header_distance = sec.footer_distance = Inches(.492)
    styles = doc.styles
    normal = styles["Normal"]
    normal.font.name = "Arial Unicode MS"; normal.font.size = Pt(10.5)
    for attr in ("ascii", "hAnsi", "eastAsia", "cs"):
        normal._element.rPr.rFonts.set(qn(f"w:{attr}"), "Arial Unicode MS")
    normal._element.rPr.rFonts.set(qn("w:hint"), "eastAsia")
    normal.paragraph_format.space_after = Pt(6); normal.paragraph_format.line_spacing = 1.25
    for key, size, color, before, after in [
        ("Heading 1",16,(36,107,253),18,10),("Heading 2",13,(36,107,253),14,7),("Heading 3",12,(25,78,168),10,5)]:
        st=styles[key]; st.font.name="Arial Unicode MS"; st.font.size=Pt(size); st.font.bold=True; st.font.color.rgb=RGBColor(*color)
        for attr in ("ascii", "hAnsi", "eastAsia", "cs"):
            st._element.rPr.rFonts.set(qn(f"w:{attr}"), "Arial Unicode MS")
        st._element.rPr.rFonts.set(qn("w:hint"), "eastAsia"); st.paragraph_format.space_before=Pt(before); st.paragraph_format.space_after=Pt(after); st.paragraph_format.keep_with_next=True
    header=sec.header.paragraphs[0]; header.text="CPT 康比特｜智能排菜系统用户操作手册"; set_font(header.runs[0],size=8.5,color=(102,112,133))
    add_page_number(sec.footer.paragraphs[0])

    # Editorial-cover header pattern.
    p=doc.add_paragraph(); p.alignment=WD_ALIGN_PARAGRAPH.CENTER; p.paragraph_format.space_before=Pt(96); p.paragraph_format.space_after=Pt(12)
    r=p.add_run("智能排菜系统"); set_font(r,size=30,bold=True,color=(23,32,51))
    p=doc.add_paragraph(); p.alignment=WD_ALIGN_PARAGRAPH.CENTER; p.paragraph_format.space_after=Pt(28)
    r=p.add_run("Android Pad 客户端用户操作手册"); set_font(r,size=17,bold=True,color=(36,107,253))
    p=doc.add_paragraph(); p.alignment=WD_ALIGN_PARAGRAPH.CENTER; p.paragraph_format.space_after=Pt(80)
    r=p.add_run("称重台排菜 · 档口菜谱维护 · 系统设置"); set_font(r,size=11,color=(102,112,133))
    for text in ["文档版本：V1.0","适用角色：餐厅运营人员、店长、实施与运维人员","最后核验：2026-07-14，公开交互原型"]:
        p=doc.add_paragraph(); p.alignment=WD_ALIGN_PARAGRAPH.CENTER; p.paragraph_format.space_after=Pt(5); set_font(p.add_run(text),size=10,color=(71,84,103))
    doc.add_page_break()

    started=False
    active_numbering_id=None
    for raw in lines:
        line=raw.rstrip()
        is_numbered = bool(re.match(r"^(\d+)\.\s+(.*)$", line))
        if not is_numbered:
            active_numbering_id=None
        if line.startswith("# "):
            if not started: started=True; continue
            doc.add_heading(line[2:],0); continue
        if line.startswith("## "):
            doc.add_paragraph(line[3:], style="Heading 1"); continue
        if line.startswith("### "):
            doc.add_paragraph(line[4:], style="Heading 2"); continue
        m_img=re.match(r"^!\[(.*)\]\((.+)\)$", line)
        if m_img:
            p=doc.add_paragraph(); p.alignment=WD_ALIGN_PARAGRAPH.CENTER; p.paragraph_format.keep_with_next=True
            p.add_run().add_picture(str(ROOT/m_img.group(2)), width=Inches(6.45))
            cap=doc.add_paragraph(); cap.alignment=WD_ALIGN_PARAGRAPH.CENTER; cap.paragraph_format.space_after=Pt(10); set_font(cap.add_run(m_img.group(1)),size=8.5,color=(102,112,133))
            continue
        if not line: continue
        if line.startswith("> "):
            p=doc.add_paragraph(); p.paragraph_format.left_indent=Inches(.18); p.paragraph_format.right_indent=Inches(.12); p.paragraph_format.space_before=Pt(5); p.paragraph_format.space_after=Pt(10)
            r=p.add_run(line[2:]); set_font(r,size=10,color=(92,64,50)); continue
        if line.startswith("- "):
            p=doc.add_paragraph(style="List Bullet"); p.paragraph_format.left_indent=Inches(.375); p.paragraph_format.first_line_indent=Inches(-.188); p.paragraph_format.space_after=Pt(4); add_inline_runs(p,line[2:]); continue
        m_num=re.match(r"^(\d+)\.\s+(.*)$", line)
        if m_num:
            p=doc.add_paragraph(style="List Number"); p.paragraph_format.left_indent=Inches(.375); p.paragraph_format.first_line_indent=Inches(-.188); p.paragraph_format.space_after=Pt(4)
            if active_numbering_id is None:
                active_numbering_id=restart_list_numbering(doc,p)
            else:
                p._p.get_or_add_pPr().get_or_add_numPr().get_or_add_numId().val=active_numbering_id
            add_inline_runs(p,m_num.group(2)); continue
        p=doc.add_paragraph();
        add_inline_runs(p,line.replace("  "," "))
    doc.save(DOCX)


lines = MD.read_text(encoding="utf-8").splitlines()
HTML.write_text(build_html(lines), encoding="utf-8")
build_docx(lines)
print(HTML)
print(DOCX)
