#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""省基金 PDF 解析 v3：浙江状态机 + 广东坐标行 + 跨行合并
校验：浙江 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'
CAT_PAT = re.compile(r'^(青基项目|探索项目|重点项目|杰青项目|重大项目|青稞项目|联合基金|地区科学基金项目|延续项目|优秀青年|杰出青年|面上|青年|重点)$')
CODE_PAT = re.compile(r'^[A-Z]{1,4}\d{2}[A-Z]?\d[\dA-Z]*$')


def lines(page, tol=2.5):
    rows = defaultdict(list)
    for w in page.get_text('words'):
        x0, y0, t = w[0], w[1], 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])
        ys = sorted(z[1] for z in items)
        out.append((ys[len(ys) // 2], [(x, t) for x, _, t in items]))
    return out


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


# ── 浙江：文本行状态机 ─────────────────────────────
doc = fitz.open(ZJ)
all_lines = []
for pno in range(doc.page_count):
    for ln in doc[pno].get_text().split('\n'):
        ln = ln.strip()
        if ln:
            all_lines.append(ln)

zrows = []
i = 0
while i < len(all_lines):
    if re.fullmatch(r'\d{1,4}', all_lines[i]):
        seq = all_lines[i]
        j = i + 1
        name_parts, code, pi, unit_parts, cat_parts = [], '', '', [], []
        # 名称直到编号
        while j < len(all_lines) and not CODE_PAT.match(all_lines[j]):
            # 防止把下一条序号吃进来
            if re.fullmatch(r'\d{1,4}', all_lines[j]) and name_parts:
                break
            name_parts.append(all_lines[j]); j += 1
        if j < len(all_lines) and CODE_PAT.match(all_lines[j]):
            code = all_lines[j]; j += 1
            # 编号可能跨行（末尾纯数字/字母）
            while j < len(all_lines) and re.fullmatch(r'[0-9A-Z]{1,3}', all_lines[j]) and not re.fullmatch(r'\d{1,4}', all_lines[j]):
                code += all_lines[j]; j += 1
        if j < len(all_lines):
            pi = all_lines[j]; j += 1
        # 单位直到类别
        while j < len(all_lines) and not CAT_PAT.match(all_lines[j]):
            if re.fullmatch(r'\d{1,4}', all_lines[j]):
                break
            unit_parts.append(all_lines[j]); j += 1
        while j < len(all_lines) and (CAT_PAT.match(all_lines[j]) or all_lines[j].startswith('联合资助方')):
            cat_parts.append(all_lines[j]); j += 1
            if cat_parts and cat_parts[-1].startswith('联合资助方'):
                break
        if code:
            zrows.append({'no': seq, 'name': ''.join(name_parts), 'code': code, 'pi': pi,
                          'unit': ''.join(unit_parts), 'cat': ' '.join(cat_parts)})
        i = j if j > i else i + 1
    else:
        i += 1

print('█ 浙江行数:', len(zrows), '（校验 2667）')
print('   类别:', {k: sum(1 for r in zrows if k in r['cat']) for k in ('重大', '杰青', '重点', '探索', '青基', '联合', '青稞')})

# ── 广东：坐标行 + 名称缓冲 ─────────────────────────
doc = fitz.open(GD)
grows = []
buf = []
for pno in range(doc.page_count):
    for y, items in lines(doc[pno]):
        name = band(items, 100, 320)
        unit = band(items, 320, 420)
        pi = band(items, 420, 470)
        amt1 = band(items, 470, 510)
        amt2 = band(items, 510, 545)
        typ = band(items, 545, 999)
        if name:
            buf.append(name)
        if re.fullmatch(r'\d+', amt1 or '') and typ:
            # 类型可能是「杰出」/「优秀」+ 下一行「青年」
            if typ in ('杰出', '优秀'):
                typ = typ + '青年'
            cat = re.sub(r'\s+', '', typ)
            grows.append({'name': ''.join(buf), 'unit': unit, 'pi': pi,
                          'amt': amt1, 'cat': cat})
            buf = []
        elif buf and unit and re.fullmatch(r'\d+', amt1 or ''):
            # 类型在下一行的情况，先记下，后续补齐
            grows.append({'name': ''.join(buf), 'unit': unit, 'pi': pi,
                          'amt': amt1, 'cat': ''})
            buf = []

for r in grows:
    r['name'] = re.sub(r'\s+', '', r['name'])
    r['unit'] = re.sub(r'\s+', '', r['unit'])
print('█ 广东行数:', len(grows), '（校验 3171）')
print('   金额合计: %d 万元（校验 42110）' % sum(int(r['amt']) for r in grows if r['amt'].isdigit()))
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=['name', 'unit', 'pi', 'amt', 'cat'])
    w.writeheader(); w.writerows(grows)
print('✅ CSV 写入 parsed/')
