#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""蛋白突变改造报告：MD → 自包含 HTML（宝锐蓝白版式，内联 CSS/Logo，零外链）
用法: /usr/bin/python3 脚本/build_protein_report.py <in.md> <out.html>
"""
import base64, html, os, re, sys
import markdown

BASE = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
LOGO = os.path.expanduser('~/work/公司资料/logo_transparent.png')
IN = sys.argv[1] if len(sys.argv) > 1 else os.path.join(BASE, '知识沉淀/蛋白突变改造_主流方案与迭代方向_20260912.md')
OUT = sys.argv[2] if len(sys.argv) > 2 else os.path.join(BASE, '知识沉淀/蛋白突变改造_主流方案与迭代方向_20260912.html')

md = open(IN, encoding='utf-8').read()
logo_b64 = base64.b64encode(open(LOGO, 'rb').read()).decode() if os.path.exists(LOGO) else ''

# ── 分节：以 ## 切分 ────────────────────────────────────────────
parts = re.split(r'^## ', md, flags=re.M)
head_blob = parts[0]
sections = []
for p in parts[1:]:
    lines = p.split('\n')
    title = lines[0].strip()
    sections.append((title, '## ' + p))

def inline(s):
    s = html.escape(str(s), quote=False)
    for a, b in [('✓全文', '<span class="pill ok">✓全文</span>'),
                 ('⚠摘要', '<span class="pill warn">⚠摘要</span>'),
                 ('未核实', '<span class="pill gray">未核实</span>'),
                 ('P0', '<span class="pill pri">P0</span>'),
                 ('P1', '<span class="pill pri1">P1</span>'),
                 ('P2', '<span class="pill pri2">P2</span>'),
                 ('P3', '<span class="pill pri3">P3</span>')]:
        s = s.replace(a, b)
    s = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', s)
    s = re.sub(r'`([^`]+?)`', r'<code>\1</code>', s)
    return s

def render(mdtext):
    # 表格单独处理（走 tables 扩展），但单元格用 inline() 上色
    h = markdown.markdown(mdtext, extensions=['tables', 'fenced_code', 'sane_lists'])
    def fix_row(m):
        row = m.group(0)
        return re.sub(r'<(td|th)>(.*?)</\1>', lambda x: '<%s>%s</%s>' % (x.group(1), inline(re.sub(r'<[^>]+>', '', x.group(2))), x.group(1)), row, flags=re.S)
    h = re.sub(r'<tr>.*?</tr>', fix_row, h, flags=re.S)
    return h

# ── KPI 卡：从 §0 的表格抽前 4 条结论 ─────────────────────────────
kpis = []
m0 = next((t for t in sections if t[0].startswith('0.')), None)
if m0:
    for row in re.findall(r'^\| (\d) \| \*\*(.+?)\*\*：(.+?) \| (.+?) \|$', m0[1], re.M)[:4]:
        kpis.append((row[0], row[1], row[2], row[3]))
if not kpis:
    for row in re.findall(r'^\| (\d) \| \*\*(.+?)\*\* (.+?) \| (.+?) \|$', m0[1], re.M)[:4] if m0 else []:
        kpis.append(row)

toc = ''.join('<li><a href="#s%d">%s</a></li>' % (i, html.escape(t)) for i, (t, _) in enumerate(sections))
lead = render(head_blob) if head_blob.strip() else ''
body = ['<section class="lead">%s</section>' % lead] if lead else []
for i, (t, blk) in enumerate(sections):
    body.append('<section id="s%d"><h2>%s</h2>%s</section>' % (i, html.escape(t), render(blk)))

kpi_html = ''
if kpis:
    kpi_html = '<div class="kpi-row">' + ''.join(
        '<div class="kpi"><div class="kpi-n">%s</div><div class="kpi-t">%s</div><div class="kpi-d">%s</div></div>'
        % (n, html.escape(t[:26]), d[:120]) for n, t, d, _ in kpis) + '</div>'

CSS = """
:root{--pri:#1F4E79;--pri2:#2E75B6;--bg:#f5f7fa;--card:#fff;--txt:#1f2328;--sub:#5b6470;--line:#e3e8ef;--ok:#0d904f;--warn:#e37400;--gray:#848b96;}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--txt);font:15px/1.75 -apple-system,"PingFang SC","Microsoft YaHei",sans-serif}
header{background:var(--pri);color:#fff;padding:22px 32px;display:flex;align-items:center;gap:16px;box-shadow:0 2px 10px rgba(0,0,0,.12)}
header img{height:38px;filter:brightness(0) invert(1)}
header .t{font-size:20px;font-weight:700;letter-spacing:.3px}
header .s{font-size:12.5px;opacity:.85;margin-top:3px}
.wrap{max-width:1180px;margin:26px auto;padding:0 20px;display:grid;grid-template-columns:236px 1fr;gap:26px}
@media(max-width:980px){.wrap{grid-template-columns:1fr}.toc{display:none}}
.toc{position:sticky;top:20px;align-self:start;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px 16px}
.toc h3{margin:2px 0 10px;font-size:13px;color:var(--sub);letter-spacing:.6px}
.toc ul{list-style:none;margin:0;padding:0;font-size:13.5px}
.toc li{margin:6px 0}
.toc a{color:var(--pri);text-decoration:none}
.toc a:hover{text-decoration:underline}
section{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:22px 26px;margin-bottom:20px;box-shadow:0 1px 3px rgba(16,24,40,.04)}
h1{font-size:24px;margin:6px 0 4px}
h2{font-size:18px;color:var(--pri);margin:2px 0 14px;padding-bottom:9px;border-bottom:2px solid var(--pri2)}
h3{font-size:15.5px;margin:18px 0 8px;color:var(--pri)}
blockquote{margin:0 0 14px;padding:10px 14px;background:#eef4fb;border-left:4px solid var(--pri2);border-radius:0 8px 8px 0;color:#33414f;font-size:13.5px}
table{width:100%;border-collapse:collapse;margin:12px 0 18px;font-size:13.5px}
th,td{border:1px solid var(--line);padding:8px 10px;text-align:left;vertical-align:top}
th{background:#eef4fb;color:var(--pri);font-weight:600;white-space:nowrap}
tr:nth-child(even) td{background:#fafbfd}
code{background:#f0f3f7;padding:1px 5px;border-radius:4px;font-size:12.5px;color:#1f4e79}
.pill{display:inline-block;padding:1px 7px;border-radius:9px;font-size:11.5px;font-weight:600;white-space:nowrap}
.pill.ok{background:#e6f6ec;color:var(--ok)}
.pill.warn{background:#fff3e0;color:var(--warn)}
.pill.gray{background:#eef0f3;color:var(--gray)}
.pill.pri{background:#e8f0fa;color:var(--pri);font-weight:700}
.pill.pri1{background:#eaf3fb;color:#2E75B6}.pill.pri2{background:#f1f0fb;color:#5b53c9}.pill.pri3{background:#f3f4f6;color:#6b7280}
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin:6px 0 22px}
.kpi{background:var(--card);border:1px solid var(--line);border-left:4px solid var(--pri2);border-radius:10px;padding:14px}
.kpi-n{font-size:22px;font-weight:800;color:var(--pri);line-height:1}
.kpi-t{font-size:13.5px;font-weight:700;margin:6px 0 4px}
.kpi-d{font-size:12.5px;color:var(--sub)}
section.lead{background:linear-gradient(180deg,#fbfdff,#fff)}
section.lead h1{margin-top:0}
footer{max-width:1180px;margin:0 auto 40px;padding:0 20px;color:var(--sub);font-size:12.5px}
"""

H = """<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>蛋白突变改造：主流方案、迭代方向与 PCR/NGS 落地可行性</title>
<style>%s</style></head><body>
<header>%s<div><div class="t">蛋白突变改造：主流方案 · 迭代方向 · PCR/NGS 落地</div>
<div class="s">宝锐生物 营销中心 · 技术情报 ｜ 2026-09-12 ｜ 证据口径：✓全文=本机已读全文 ⚠摘要=仅题录</div></div></header>
<div class="wrap"><nav class="toc"><h3>目录</h3><ul>%s</ul></nav><main>%s%s</main></div>
<footer>本页由脚本生成（脚本/build_protein_report.py）。所有数字与结论均标注来源等级；未获来源之数字标「未核实」。本页自包含，无任何外部依赖。</footer>
</body></html>"""
out = H % (CSS, ('<img src="data:image/png;base64,%s" alt="BIORI">' % logo_b64) if logo_b64 else '',
           toc, kpi_html, ''.join(body))
open(OUT, 'w', encoding='utf-8').write(out)

ext = len(re.findall(r'(?:src|href)="https?://', out))
print('✓ 已生成 %s' % OUT)
print('  %.1f KB ｜ 节数 %d ｜ KPI 卡 %d ｜ 表格 %d ｜ 外链引用 %d ｜ logo 内联 %s'
      % (os.path.getsize(OUT)/1024, len(sections), len(kpis), out.count('<table'), ext, bool(logo_b64)))
