#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""从说明书 PDF 抽出结构化「体系配制表」与「推荐反应程序」，并与核心货号对齐。

产出：数据/manual_tables.json
  每个货号：{货号, 说明书文件, 页数, 体系配制: [{页, 表格: [[...]], 文本}], 反应程序: [...], 备注}
说明：表格来自 PDF 真实表格识别（find_tables），文本为同页原文；均记录页码，可点回 PDF 核对。
"""
import json
import os
import re

import fitz

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
PDF_DIR = os.path.join(ROOT, '资料/说明书')
OUT = os.path.join(ROOT, '数据/manual_tables.json')
KW_SYS = ['体系配制', '反应体系', '配制体系', '体系组成', '反应液配制', 'PCR 体系', 'PCR体系', '组分', '用量']
KW_PROG = ['反应程序', '循环条件', '扩增程序', '反应条件', '预变性', '退火', '延伸', '循环数', '采集荧光']


def clean(s):
    return re.sub(r'\s+', ' ', str(s or '')).strip()


def parse_pdf(path):
    doc = fitz.open(path)
    sys_pages, prog_pages = [], []
    for i, pg in enumerate(doc, 1):
        t = pg.get_text('text')
        if any(k in t for k in KW_SYS) and not sys_pages:
            sys_pages.append(i)
        elif any(k in t for k in KW_SYS) and i not in sys_pages and len(sys_pages) < 3:
            sys_pages.append(i)
        if any(k in t for k in KW_PROG):
            prog_pages.append(i)
    out = {'体系配制': [], '反应程序': []}
    for tag, pages, kws in (('体系配制', sys_pages[:3], KW_SYS), ('反应程序', prog_pages[:3], KW_PROG)):
        for pno in pages:
            pg = doc[pno - 1]
            tables = []
            try:
                for tb in (pg.find_tables() or []):
                    rows = [[clean(c) for c in row] for row in tb.extract()]
                    if len(rows) >= 2:
                        tables.append(rows)
            except Exception:
                pass
            txt = pg.get_text('text')
            # 截取关键词附近的原文块（保留原文，供无表格时展示）
            blocks = []
            for part in re.split(r'\n(?=[^\n])', txt):
                if any(k in part for k in kws) and len(part) < 600:
                    blocks.append(re.sub(r'\n{2,}', '\n', part).strip())
            out[tag].append({'页': pno, '表格': tables, '文本块': blocks[:4]})
    out['页数'] = doc.page_count
    return out


def main():
    res = {}
    files = [f for f in sorted(os.listdir(PDF_DIR)) if f.endswith('.pdf')]
    print('说明书 PDF %d 份' % len(files))
    for i, f in enumerate(files, 1):
        key = re.sub(r'_说明书.*$', '', f).replace('.pdf', '')
        try:
            d = parse_pdf(os.path.join(PDF_DIR, f))
        except Exception as e:
            print('  ✗ %s: %s' % (f, e))
            continue
        d['说明书文件'] = f
        d['体系配制表数'] = sum(len(x['表格']) for x in d['体系配制'])
        d['程序页数'] = len(d['反应程序'])
        res[key.upper()] = d
        if i % 40 == 0:
            print('  已解析 %d/%d' % (i, len(files)))
    json.dump({'生成时间': __import__('time').strftime('%Y-%m-%d %H:%M'), '说明书数': len(res), 'items': res},
              open(OUT, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
    with_tab = sum(1 for v in res.values() if v['体系配制表数'])
    with_prog = sum(1 for v in res.values() if v['程序页数'])
    print('解析完成 %d 份 ｜ 含体系表 %d ｜ 含程序页 %d ｜ %.1f KB' % (
        len(res), with_tab, with_prog, os.path.getsize(OUT) / 1024.0))
    for k in ('M2071', 'HW205-P01', 'E13'):
        if k in res:
            v = res[k]
            print('\n══ %s ══' % k)
            for s in v['体系配制'][:1]:
                print('  体系表(第%s页):' % s['页'], s['表格'][:2] if s['表格'] else s['文本块'][:1])
            for s in v['反应程序'][:1]:
                print('  程序(第%s页):' % s['页'], (s['表格'][:2] if s['表格'] else s['文本块'][:2]))


if __name__ == '__main__':
    main()
