#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Q3 汇报 MD 转写验收：逐份反查 ① 附件数 ② run 级完整性 ③ 表格数 ④ 备注页数。"""
import json
import os
import re
import zipfile

ROOT = '/Users/liuxinyuan/Desktop/hermas输入-工作台数据库/2026年3季度汇报/2026年3季度汇报'
CACHE = os.path.expanduser('~/.hermes/profiles/zone-b/cache/documents')
MD = '/Users/liuxinyuan/Desktop/Hermes输出-工作类/对外物料/2026Q3汇报_MD'


FOOTER_OK = ('守护生命健康', '缔造美好生活', 'BIORI', '宝锐生物', 'www.biori.com', 'marketing@biori.com')


def html_unesc(s):
    return (s.replace('&amp;', '&').replace('&lt;', '<').replace('&gt;', '>')
             .replace('&quot;', '"').replace('&apos;', "'"))


def is_footer(s):
    t = re.sub(r'[\s·・]+', '', s)
    return (not t) or any(f.replace(' ', '') in t for f in FOOTER_OK) or re.fullmatch(r'\d{1,3}', t)


def norm(s):
    s = re.sub(r'[\s\u3000]+', '', s)
    s = re.sub(r'[*_`>#|\-—·・…]', '', s)
    return s


ppts = []
for root, dirs, fs in os.walk(ROOT):
    for f in sorted(fs):
        if f.endswith('.pptx') and not f.startswith('.') and '转正答辩' not in f:
            ppts.append(os.path.join(root, f))
ppts.append(os.path.join(CACHE, 'doc_e440ed352618_诊断原料-2026年三季度销售工作汇报（销售人员版本）.pptx'))

print('%-40s %6s %6s %6s %8s %6s %8s' % ('PPT', '页', 'run', '未转写', '已标/应标', '附件', '结论'))
report, bad_total = [], 0
for p in ppts:
    z = zipfile.ZipFile(p)
    names = z.namelist()
    emb = [n for n in names if re.match(r'ppt/embeddings/', n) and not n.endswith('/')]
    slides = sorted([n for n in names if re.match(r'ppt/slides/slide\d+\.xml$', n)],
                    key=lambda s: int(re.findall(r'\d+', s)[-1]))
    all_runs = []
    for s in slides:
        all_runs += [re.sub(r'\s+', ' ', r).strip() for r in
                     re.findall(r'<a:t>(.*?)</a:t>', z.read(s).decode('utf-8', 'ignore'))]
    mdp = None
    for root, dirs, fs in os.walk(MD):
        for f in fs:
            if f.endswith('.md') and os.path.basename(p).replace('.pptx', '')[:20] in f:
                mdp = os.path.join(root, f)
    if not mdp:
        if os.path.basename(p).startswith('doc_'):
            print('— 跳过重复投递件：%s' % os.path.basename(p)[:38])
            continue
        print('✗ 缺 md：%s' % os.path.basename(p)[:38])
        continue
    body = norm(open(mdp, encoding='utf-8').read())
    miss = []
    for r in set(all_runs):
        if is_footer(r):
            continue
        r2 = norm(html_unesc(r))
        if len(r2) < 2:
            continue
        if r2 not in body:
            miss.append(r)
    ole_marked = len(re.findall(r'📎', open(mdp, encoding='utf-8').read()))
    # 页内真实引用的 OLE 数量（按 (slide, rId) 去重）
    refs, ref_targets = set(), set()
    for s in slides:
        x = z.read(s).decode('utf-8', 'ignore')
        rels = 'ppt/slides/_rels/' + os.path.basename(s) + '.rels'
        r2t = {}
        if rels in names:
            r2t = {m[0]: 'ppt/' + m[1].replace('../', '') for m in
                   re.findall(r'Id="(rId\d+)"[^>]*Target="([^"]+)"', z.read(rels).decode('utf-8', 'ignore'))}
        for m in re.finditer(r'<p:oleObj[^>]*>', x):
            rid = re.search(r'r:id="([^"]+)"', m.group(0))
            if rid:
                refs.add((s, rid.group(1)))
                ref_targets.add(os.path.basename(r2t.get(rid.group(1), '')))
    orphan = [os.path.basename(e) for e in emb if os.path.basename(e) not in ref_targets]
    ok = (not miss) and (ole_marked == len(refs))
    bad_total += (0 if ok else 1)
    print('%-40s %6d %6d %6d %4d/%-4d %6d %8s%s' % (os.path.basename(p)[:38], len(slides), len(all_runs),
                                                    len(miss), ole_marked, len(refs), len(emb),
                                                    '✅' if ok else '❌',
                                                    ('  孤儿附件：%s' % orphan) if orphan else ''))
    if miss:
        print('      未转写示例：%s' % miss[:4])
    report.append({'ppt': os.path.basename(p), '页': len(slides), 'run': len(all_runs),
                   '未转写': len(miss), '附件': len(emb), '已标附件': ole_marked,
                   '未转写示例': miss[:8]})
print()
print('不合格份数：%d ｜ 报告 → %s/_验收报告.json' % (bad_total, MD))
json.dump(report, open(os.path.join(MD, '_验收报告.json'), 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
