#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""竞品证据挖掘 v2 —— 精度优先（修正 v1 的泛词误匹配）。

v1 问题：用「品名里的英文词」匹配活动文本，导致同一批泛词把所有货号都命中，
每个货号都得到一模一样的品牌计数 —— 属于噪声，不可用于交付。

v2 口径：
  A. 货号级（高精度）：活动原文里**出现该货号字符串**（或父货号），且同时提到竞品品牌。
  B. 系列级（中等精度）：按**产品系列名**（如 FastAmpli / SensiDirect / Robustart / Neoscript）聚合，
     同系列家族共用，明确标注"系列级，非单货号结论"。
  两档分开存放，证据全部保留原文/客户/日期，可追溯。
"""
import json
import os
import re
from collections import Counter, defaultdict

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
CORE = os.path.join(ROOT, '数据/diag_sku_core.json')
ACT = os.path.join(ROOT, '数据/activities_feishu.json')

BRANDS = ['诺唯赞', '翌圣', '菲鹏', '瀚海新酶', '全式金', '康为世纪', '康为', '宝创', '致善', '迈迪安',
          '赛默飞', 'Thermo', 'Takara', '宝生物', '近岸', '义翘', '金斯瑞', '吐露港', '艾科瑞',
          'ABclonal', '爱博泰克', 'Toyobo', 'NEB', 'Roche', '罗氏', 'Promega', 'Sigma', 'Merck',
          '默克', '碧云天', '生工', '擎科', '华大']
STOP = {'premix', 'master', 'probe', 'plus', 'fast', 'direct', 'pcr', 'qpcr', 'ung', 'dna', 'rna',
        'mix', 'series', 'buffer', 'kit', 'enzyme', 'polymerase', 'reverse', 'transcriptase'}
GENERIC = {'taq', 'bst', 'tth', 'dntp', 'bsa', 'rnase', 'buffer', 'premix', 'probe', 'qpcr'}


def brands_in(text):
    return sorted({b for b in BRANDS if b in text})


def family_of(name):
    fams = set()
    for m in re.findall(r'[A-Za-z][A-Za-z0-9\-]{3,}', str(name or '')):
        t = m.strip('-')
        low = t.lower()
        if low in STOP or low in GENERIC or len(t) < 5:
            continue
        if re.search(r'[A-Z]', t[1:]):
            fams.add(t)
    for m in re.findall(r'[\u4e00-\u9fff]{2,8}(?:系列|预混液|全预混)', str(name or '')):
        fams.add(m)
    return sorted(fams)


def main():
    core = json.load(open(CORE, encoding='utf-8'))
    acts = json.load(open(ACT, encoding='utf-8'))['items']
    prepared = [{'date': a.get('date'), 'customer': a.get('customer'), 'sales': a.get('sales'),
                 'low': (str(a.get('text') or '') + ' ' + str(a.get('type') or '')).lower(),
                 'raw': re.sub(r'\s+', ' ', str(a.get('text') or ''))[:170],
                 'brands': brands_in(str(a.get('text') or '') + str(a.get('type') or ''))} for a in acts]

    fam_index = defaultdict(list)
    for rec in core['items']:
        rec['系列'] = family_of(rec.get('品名') or rec.get('品名内'))
        for f in rec['系列']:
            fam = f.lower()
            for a in prepared:
                if fam in a['low']:
                    fam_index[f].append(a)

    sku_hits = fam_hits = 0
    for rec in core['items']:
        sku = rec['货号'].lower()
        parent = re.sub(r'-\d{3,}.*$', '', sku)
        ev = []
        for a in prepared:
            if a['brands'] and (sku in a['low'] or (len(parent) >= 5 and parent in a['low'])):
                ev.append({'日期': a['date'], '客户': a['customer'], '销售': a['sales'],
                           '竞品': a['brands'], '原文': a['raw']})
        rec['竞品证据_货号级'] = ev[:8]
        if ev:
            sku_hits += 1
        sev = {}
        for f in rec['系列']:
            got = [a for a in fam_index.get(f, []) if a['brands']]
            if got:
                sev[f] = {'提及条数': len(got),
                          '品牌热度': dict(Counter(b for a in got for b in a['brands']).most_common(6)),
                          '样例': [{'日期': a['date'], '客户': a['customer'], '竞品': a['brands'],
                                   '原文': a['raw']} for a in got[:4]]}
        rec['竞品证据_系列级'] = sev
        if sev:
            fam_hits += 1
        for k in ('竞品证据', '竞品品牌热度', '匹配用关键词'):
            rec.pop(k, None)

    core['竞品口径'] = ('诊断原料线无货号级竞品对标表。本模块分两档：'
                   '【货号级】= 活动原文出现该货号字符串；'
                   '【系列级】= 按产品系列名聚合，家族共用，非单货号结论。'
                   '证据均保留原文/客户/日期，可追溯。产品参数级对比缺失，标「待补」。')
    core['统计']['竞品证据_货号级命中'] = sku_hits
    core['统计']['竞品证据_系列级命中'] = fam_hits
    json.dump(core, open(CORE, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
    print('货号级命中 %d ｜ 系列级命中 %d（共 %d 个货号）' % (sku_hits, fam_hits, len(core['items'])))
    print()
    for rec in core['items']:
        if rec.get('竞品证据_货号级'):
            print('  ✅ %-18s 货号级 %d 条 ｜ %s' % (rec['货号'], len(rec['竞品证据_货号级']),
                  (rec.get('品名') or '')[:32]))
    print()
    for rec in core['items'][:8]:
        if rec.get('竞品证据_系列级'):
            print('  ○ %-14s %s → %s' % (rec['货号'], rec['系列'],
                  {k: v['品牌热度'] for k, v in rec['竞品证据_系列级'].items()}))
    print('\n→ 已写回', CORE)


if __name__ == '__main__':
    main()
