#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""省基金 → 宝锐产品线映射 + 单位级聚合
输入：parsed/浙江_2026省基金_明细.csv、parsed/广东_2026省基金_明细.csv
输出：数据/科研经费_两省产品线映射.json、销售分析/科研经费_单位级清单_广东浙江_2026.xlsx
口径：
  - 生医相关：浙江按学科代码 C/H；广东按项目名称关键词
  - 产品线权重：经验值（用户已确认 30/20/15/5/10/20），按关键词微调
  - 浙江金额：按类别标准额测算（重大100/杰青80/重点30/探索10/青基10/青稞10/联合按子类）
"""
import csv
import io
import json
import os
import re
from collections import Counter, defaultdict

BASE = '/Users/liuxinyuan/Desktop/Hermes输出-工作类/销售分析/基金源文件'
OUT_JSON = '/Users/liuxinyuan/Desktop/Hermes输出-工作类/数据/科研经费_两省产品线映射.json'

# ── 产品线定义与经验权重（用户 2026-10 确认，标注经验值）──
LINES = ['分子·RT-qPCR', '分子·PCR/克隆', '分子·核酸提取', '分子·LAMP/恒温', '分子·其他', 'WB']
BASE_W = {'分子·RT-qPCR': 30, '分子·PCR/克隆': 20, '分子·核酸提取': 15,
          '分子·LAMP/恒温': 5, '分子·其他': 10, 'WB': 20}

KW = {
    '分子·RT-qPCR': ['表达', '转录', 'qPCR', '定量', '检测', 'RNA', 'mRNA', '非编码', 'lncRNA', 'circRNA', 'miRNA', '逆转录', 'real-time'],
    '分子·PCR/克隆': ['克隆', '载体', '质粒', '编辑', 'CRISPR', '突变', '扩增', 'PCR', '构建', '重组', '文库', '转化', '转染', '敲除', '敲入', '过表达'],
    '分子·核酸提取': ['提取', '纯化', '分离', '富集', '样本', '核酸', 'DNA', '基因组', '测序', '甲基化', '单细胞'],
    '分子·LAMP/恒温': ['LAMP', '环介导', '恒温', '等温', 'POCT', '现场', '快速检测', '床旁', '试纸条', '冻干'],
    '分子·其他': ['电泳', 'Marker', 'dNTP', '缓冲', '试剂盒', '酶'],
    'WB': ['蛋白', '抗体', '免疫', '信号', '通路', '磷酸化', '乙酰化', '泛素', '修饰', '互作', '复合物', '亚细胞', '定位', '表达水平', '蛋白组', '免疫组化', '免疫荧光', 'Western', '印迹', '受体', '激酶'],
}
BIO_KW = ['基因', '蛋白', '细胞', '免疫', '分子', '微生物', '病毒', '菌', '肿瘤', '癌', '疾病', '临床', '药物', 'RNA', 'DNA', '代谢', '神经', '干细胞',
          '组织', '器官', '病理', '药理', '中医', '中药', '护理', '公共卫生', '流行病', '队列', '样本', '诊断', '治疗', '靶点', '受体', '酶', '抗体', '疫苗',
          '感染', '炎症', '心血管', '糖尿病', '肝', '肾', '肺', '脑', '骨', '眼', '口腔', '生殖', '发育', '遗传', '表观', '转录', '信号', '通路', '生物',
          '医学', '药学', '检验', '影像', '健康', '衰老', '氧化', '应激', '凋亡', '自噬', '分化', '增殖', '迁移', '侵袭', '转移']

ZJ_AMT = [('重大', 100), ('杰青', 80), ('重点', 30), ('探索', 10), ('青基', 10), ('青稞', 10), ('地区', 10), ('延续', 80)]


def line_weights(title):
    """关键词打分 → 产品线分布（经验权重作先验）"""
    t = title or ''
    score = {}
    for ln, kws in KW.items():
        hits = sum(1 for k in kws if k.lower() in t.lower())
        score[ln] = hits
    if sum(score.values()) == 0:
        return dict(BASE_W)
    # 先验 × (1+2×命中)，再归一
    raw = {ln: BASE_W[ln] * (1 + 2 * score[ln]) for ln in LINES}
    s = sum(raw.values())
    return {ln: raw[ln] / s * 100 for ln in LINES}


def is_bio_gd(title):
    return any(k.lower() in (title or '').lower() for k in BIO_KW)


def zj_amt(cat):
    for k, v in ZJ_AMT:
        if k in cat:
            return v
    return 10


def unit_type(u):
    if re.search(r'(医院|卫生院|疾控|防治中心)', u):
        return '医院'
    if re.search(r'(大学|学院|学校)', u):
        return '高校'
    if re.search(r'(研究院|研究所|实验室|科学院|中心)', u):
        return '院所'
    if re.search(r'(公司|集团|企业)', u):
        return '企业'
    return '其他'


# ── 浙江 ──
zj = [r for r in csv.DictReader(io.open(BASE + '/parsed/浙江_2026省基金_明细.csv', encoding='utf-8-sig'))
      if r['no'].isdigit() and int(r['no']) <= 2667]
for r in zj:
    m = re.search(r'26([A-H])', r['code'] or '')
    r['disc'] = m.group(1) if m else '?'
    r['bio'] = r['disc'] in ('C', 'H')
    r['amt'] = zj_amt(r['cat'])
    r['w'] = line_weights(r['name']) if r['bio'] else None

# ── 广东 ──
gd = list(csv.DictReader(io.open(BASE + '/parsed/广东_2026省基金_明细.csv', encoding='utf-8-sig')))
for r in gd:
    r['amt'] = int(r['amt'])
    r['bio'] = is_bio_gd(r['name'])
    r['w'] = line_weights(r['name']) if r['bio'] else None

print('浙江 %d 项 / %.0f 万元 ｜ 生医 %d 项 / %.0f 万元' % (
    len(zj), sum(r['amt'] for r in zj),
    sum(1 for r in zj if r['bio']), sum(r['amt'] for r in zj if r['bio'])))
print('广东 %d 项 / %d 万元 ｜ 生医 %d 项 / %d 万元' % (
    len(gd), sum(r['amt'] for r in gd),
    sum(1 for r in gd if r['bio']), sum(r['amt'] for r in gd if r['bio'])))


def agg(rows):
    out = {ln: 0.0 for ln in LINES}
    for r in rows:
        if not r['bio']:
            continue
        for ln in LINES:
            out[ln] += r['amt'] * r['w'][ln] / 100
    return out


res = {}
for prov, rows in (('浙江', zj), ('广东', gd)):
    bio_rows = [r for r in rows if r['bio']]
    by_line = agg(rows)
    unit = defaultdict(lambda: {'n': 0, 'amt': 0, 'bio_n': 0, 'bio_amt': 0, 'lines': {ln: 0.0 for ln in LINES}})
    for r in rows:
        u = unit[r['unit']]
        u['n'] += 1; u['amt'] += r['amt']
        if r['bio']:
            u['bio_n'] += 1; u['bio_amt'] += r['amt']
            for ln in LINES:
                u['lines'][ln] += r['amt'] * r['w'][ln] / 100
    units = [{'unit': k, 'type': unit_type(k), **v} for k, v in unit.items()]
    units.sort(key=lambda x: -x['bio_amt'])
    res[prov] = {
        'total_n': len(rows), 'total_amt': sum(r['amt'] for r in rows),
        'bio_n': len(bio_rows), 'bio_amt': sum(r['amt'] for r in bio_rows),
        'by_line': {k: round(v, 1) for k, v in by_line.items()},
        'units': units,
    }
    print('\n█ %s ｜生医 %d 项 / %d 万元 ｜产品线:' % (prov, len(bio_rows), sum(r['amt'] for r in bio_rows)))
    for ln in LINES:
        print('   %-14s %8.1f 万元  %5.1f%%' % (ln, by_line[ln], by_line[ln] / max(1, sum(by_line.values())) * 100))

os.makedirs(os.path.dirname(OUT_JSON), exist_ok=True)
io.open(OUT_JSON, 'w', encoding='utf-8').write(json.dumps({
    'meta': {'source': '广东/浙江 2026 省自然科学基金拟立项清单（官方 PDF）',
             'weights': BASE_W, 'weight_note': '经验值（用户确认），非官方统计口径',
             'zj_total_n': len(zj), 'gd_total_n': len(gd)},
    'provinces': res}, ensure_ascii=False, indent=1))
print('\n✅', OUT_JSON)
