#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
把 ERP 订单备注提取结果 → 客户特殊要求库（+ 复核件）
=====================================================
口径（用户 2026-09-20）：**只统计 ERP 导出订单备注里的特殊要求，不统计飞书活动里提出的**。

输入：数据/_erp_sr_extracted.json（脚本 extract_erp_remarks.py 产出）
用法：
  python3 build_erp_special_requirements.py --review   # 只出复核件（数据/sr_review.json）
  python3 build_erp_special_requirements.py --apply    # 复核件 + 写入正式库（会先备份）
  python3 build_erp_special_requirements.py --apply --keep-feishu   # 保留原飞书来源条目（默认清空重来）

条目字段：客户 / 类别 / 标题 / 内容 / 货号 / 状态 / 归属人(owner，判权用) / 来源(ERP单据编号+日期) / 备注原文
状态规则：置信度=高 → active（生效）；中/低 → pending（页面标「⏳ 待复核」）
校验拦下（不进库，只在复核页可见）：缺客户 / 掩码客户 / 缺原文依据 / 内容过短 / 疑似客诉
"""
import os
import re
import sys
import json
import shutil
from datetime import datetime

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SRC = os.path.join(ROOT, '数据', '_erp_sr_extracted.json')
REVIEW = os.path.join(ROOT, '数据', 'sr_review.json')
LIB = os.path.join(ROOT, '数据', 'customer_special_requirements.json')
CATS = ['搭配规则', '配方/体系', '包装/标签', '交付/物流', '质检/文件', '价格/账期', '其他']
MASK = re.compile(r'^\*+$|^nan$|^未知|^宝锐|^珠海宝锐|宝泰仪')
# 客诉/问题描述（不是「要求」）→ 不入库，人工复核
COMPLAINT = re.compile(r'客诉|投诉|退货|换货|索赔|质量事故')


def _s(v):
    if v is None:
        return ''
    t = str(v).strip()
    return '' if t.lower() in ('nan', 'none', 'null', 'nat') else t


def validate(it):
    probs = []
    cust = _s(it.get('客户'))
    if not cust:
        probs.append('缺客户')
    elif MASK.search(cust):
        probs.append('客户名无效（掩码/内部主体）')
    cat = _s(it.get('类别')) or '其他'
    if cat not in CATS:
        cat = '其他'
    ev = _s(it.get('依据'))
    if not ev:
        probs.append('缺原文依据')
    content = _s(it.get('内容'))
    if len(content) < 6:
        probs.append('内容过短')
    if re.search(r'本单|该订单|本次', content) and not re.search(r'要求|需|不得|必须|请|按', content):
        probs.append('疑似一次性处理（非持续性要求）')
    if COMPLAINT.search(content) or COMPLAINT.search(ev):
        probs.append('疑似客诉/问题描述')
    conf = _s(it.get('置信度')) or '中'
    if conf not in ('高', '中', '低'):
        conf = '中'
    return {'customer': cust, 'category': cat, 'title': _s(it.get('标题')), 'content': content,
            'skus': [str(s) for s in (it.get('涉及货号') or []) if str(s).strip()][:6],
            'evidence': ev, 'confidence': conf,
            'activity_id': _s(it.get('单据编号')), 'activity_date': _s(it.get('日期')),
            'activity_owner': _s(it.get('销售员')), 'activity_type': 'ERP订单备注',
            'hits': it.get('出现次数') or 1, 'src': 'ERP订单备注',
            'ok': not probs, 'problems': probs}


def load_rows():
    if not os.path.exists(SRC):
        sys.exit('  找不到 %s，先跑 extract_erp_remarks.py --merge' % SRC)
    raw = json.load(open(SRC, encoding='utf-8'))
    items = raw.get('items') or []
    rows = [validate(it) for it in items]
    # 去重：客户 + 内容前 40 字
    seen, uniq = set(), []
    for r in rows:
        k = (r['customer'], re.sub(r'\s+', '', r['content'][:40]))
        if k in seen:
            continue
        seen.add(k)
        uniq.append(r)
    return uniq


def write_review(rows):
    from collections import Counter
    clean = [r for r in rows if r['ok']]
    data = {
        'generated': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'source': 'ERP 销售订单导出备注字段（备注(内部)/备注(客户)）· 智谱GLM 提取',
        'total_raw': len(rows), 'total_after_dedupe': len(rows), 'clean': len(clean),
        'with_problems': len(rows) - len(clean),
        'by_customer': len({r['customer'] for r in rows}),
        'by_category': dict(Counter(r['category'] for r in rows)),
        'by_confidence': dict(Counter(r['confidence'] for r in rows)),
        'top_customers': [[k, v] for k, v in Counter(r['customer'] for r in rows).most_common(12)],
        'rows': rows,
    }
    json.dump(data, open(REVIEW, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
    print('  ✅ 复核件 %d 行（干净 %d ｜ 有疑点 %d）→ %s' % (len(rows), len(clean), len(rows) - len(clean), REVIEW))
    print('     按类别:', dict(data['by_category']))
    print('     按置信度:', dict(data['by_confidence']))
    print('     条目最多的客户:', '、'.join('%s(%d)' % (k[:18], v) for k, v in data['top_customers'][:8]))
    return data


def apply(rows, keep_feishu=False):
    rows = [r for r in rows if r['ok']]
    lib = {'version': 1, 'updated_at': '', 'categories': CATS, 'items': []}
    if keep_feishu and os.path.exists(LIB):
        try:
            lib = json.load(open(LIB, encoding='utf-8'))
        except Exception:
            pass
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    have = lib.get('items') or []
    keys = {(i.get('customer'), re.sub(r'\s+', '', (i.get('content') or '')[:40])) for i in have}
    n = 0
    for r in rows:
        k = (r['customer'], re.sub(r'\s+', '', r['content'][:40]))
        if k in keys:
            continue
        keys.add(k)
        n += 1
        have.append({
            'id': 'ERP-%04d' % n,
            'customer': r['customer'], 'category': r['category'],
            'title': r['title'] or r['content'][:16], 'content': r['content'], 'skus': r['skus'],
            'status': 'active' if r['confidence'] == '高' else 'pending',
            'owner': r['activity_owner'],
            'created_by': '智谱GLM从ERP订单备注提取',
            'created_at': now, 'updated_at': now,
            'source': 'ERP订单 %s（%s）' % (r['activity_id'] or '无单据号', r['activity_date'] or '日期未知'),
            'note': ('备注原文：%s' % r['evidence'])[:300] + ('（该要求在 %d 张订单中出现）' % r['hits'] if r['hits'] > 1 else ''),
        })
    lib['items'] = have
    lib['version'] = int(lib.get('version') or 1) + 1
    lib['updated_at'] = now
    shutil.copy2(LIB, LIB + '.bak_before_erp_' + datetime.now().strftime('%H%M%S'))
    json.dump(lib, open(LIB, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
    print('  ✅ 并入 %d 条 → 库现有 %d 条 → %s' % (n, len(have), LIB))


if __name__ == '__main__':
    a = sys.argv[1:]
    rows = load_rows()
    write_review(rows)
    if '--apply' in a:
        apply(rows, keep_feishu='--keep-feishu' in a)
