#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""按坐标聚类解析广东/浙江 2026 省基金 PDF（校验：浙江 2667 项；广东 3171 项 / 42110 万元）"""
import csv
import io
import os
import re
from collections import defaultdict

import fitz

BASE = '/Users/liuxinyuan/Desktop/Hermes输出-工作类/销售分析/基金源文件'
ZJ = BASE + '/浙江_2026省自然科学基金拟资助项目清单.pdf'
GD = BASE + '/广东_2026省自然科学基金拟立项及资金安排表_转载件.pdf'


def lines_of(page, tol=2.5):
    """按 y 聚类成行，返回 [(y, [(x, text), ...]), ...]"""
    rows = defaultdict(list)
    for w in page.get_text('words'):
        x0, y0, x1, y1, t = w[0], w[1], w[2], w[3], w[4]
        rows[round(y0 / tol)].append((x0, y0, t))
    out = []
    for k in sorted(rows):
        items = sorted(rows[k], key=lambda z: z[0])
        # 同一 y 簇内可能有多个基线，取中位 y
        ys = sorted(z[1] for z in items)
        out.append((ys[len(ys) // 2], [(x, t) for x, _, t in items]))
    return out


def cell_text(items, lo, hi):
    return ''.join(t for x, t in items if lo <= x < hi).strip()


# ── 浙江：x 分区 68(序号) / 91-290(名称) / 292(编号) / 350(申请人) / 382(单位) / 448(类别)
zrows = []
doc = fitz.open(ZJ)
cur = None
for pno in range(doc.page_count):
    for y, items in lines_of(doc[pno]):
        no = cell_text(items, 0, 80)
        name = cell_text(items, 85, 290)
        code = cell_text(items, 290, 348)
        pi = cell_text(items, 348, 380)
        unit = cell_text(items, 380, 445)
        cat = cell_text(items, 445, 999)
        if re.fullmatch(r'\d{1,4}', no) and (name or code):
            if cur:
                zrows.append(cur)
            cur = {'no': no, 'name': name, 'code': code, 'pi': pi, 'unit': unit, 'cat': cat}
        elif cur:
            # 续行：名称/单位换行
            if name and not code and not cat:
                cur['name'] += name
            if unit and not pi:
                cur['unit'] += unit
            if cat and not cur['cat']:
                cur['cat'] = cat
if cur:
    zrows.append(cur)

# 清理：编号缺失的行丢弃；名称换行拼接
zrows = [r for r in zrows if re.match(r'[A-Z]{1,2}\d{2}', r['code'])]
for r in zrows:
    r['name'] = re.sub(r'\s+', '', r['name'])
    r['unit'] = re.sub(r'\s+', '', r['unit'])
print('█ 浙江行数:', len(zrows), '（校验值 2667）')
print('   类别:', {k: sum(1 for r in zrows if k in r['cat']) for k in ('重大', '杰青', '重点', '探索', '青年', '联合', '青稞')})

# ── 广东：x 分区 31(序号) 71(主管) 121-320(名称) 329(单位) 425(负责人) 481/523(金额) 552(类型)
grows = []
doc = fitz.open(GD)
cur = None
for pno in range(doc.page_count):
    for y, items in lines_of(doc[pno]):
        no = cell_text(items, 0, 60)
        name = cell_text(items, 100, 320)
        unit = cell_text(items, 320, 420)
        pi = cell_text(items, 420, 470)
        amt1 = cell_text(items, 470, 510)
        amt2 = cell_text(items, 510, 545)
        typ = cell_text(items, 545, 999)
        is_head = bool(re.search(r'(面上|青年|重点|杰青|探索|重大)', typ)) and (amt1 or amt2)
        if is_head:
            if cur:
                grows.append(cur)
            cur = {'no': no, 'name': name, 'unit': unit, 'pi': pi,
                   'amt': amt1 or amt2, 'cat': re.sub(r'\s+', '', typ)}
        elif cur:
            if name and not unit:
                cur['name'] += name
            elif unit and not cur['unit']:
                cur['unit'] = unit
if cur:
    grows.append(cur)

for r in grows:
    r['name'] = re.sub(r'\s+', '', r['name'])
    r['unit'] = re.sub(r'\s+', '', r['unit'])
print('█ 广东行数:', len(grows), '（校验值 3171）')
tot = sum(float(r['amt']) for r in grows if re.fullmatch(r'\d+(\.\d+)?', r['amt']))
print('   金额合计: %.0f 万元（校验值 42110）' % tot)
print('   类型:', {k: sum(1 for r in grows if k in r['cat']) for k in ('面上', '青年', '重点', '杰青', '探索')})

os.makedirs(BASE + '/parsed', exist_ok=True)
with io.open(BASE + '/parsed/浙江_2026省基金_明细.csv', 'w', encoding='utf-8-sig', newline='') as f:
    w = csv.DictWriter(f, fieldnames=['no', 'name', 'code', 'pi', 'unit', 'cat'])
    w.writeheader(); w.writerows(zrows)
with io.open(BASE + '/parsed/广东_2026省基金_明细.csv', 'w', encoding='utf-8-sig', newline='') as f:
    w = csv.DictWriter(f, fieldnames=['no', 'name', 'unit', 'pi', 'amt', 'cat'])
    w.writeheader(); w.writerows(grows)
print('✅ parsed/*.csv')
