#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""后端：拜访与活动统计改为按飞书「活动类型」分桶（线下拜访/线上跟进/陌拜/协同拜访/未填）。

不再有文本推断：活动形式 = 飞书 field_76654e 原值。
替换区间：`offline = online = noclass = 0` … `'customers': sorted(cust.values()...`（含 return）。
"""
import io
import os
import shutil
import sys
import time

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
F = os.path.join(ROOT, '脚本', '销售工作台服务.py')

CONST_ANCHOR = "DEPT_SPLIT = {"
CONST_NEW = """ACT_TYPES = ['线下拜访', '线上跟进', '陌拜', '协同拜访']      # 飞书「活动类型」field_76654e 的选项，顺序=展示顺序
CH_OF_TYPE = {'offline': '线下拜访', 'online': '线上跟进', 'cold': '陌拜', 'joint': '协同拜访'}


DEPT_SPLIT = {"""

OLD_HEAD = """            offline = online = noclass = 0
            cust = {}
"""
OLD_TAIL = """                             'customers': sorted(cust.values(), key=lambda d: -d['total'])})
            return
"""

NEW = '''            def _atype(x):
                """活动形式 = 飞书「活动类型」原值（field_76654e）；工作台自记的走 channel 映射。

                不用文本推断：飞书该字段 100% 有值，推断出来的「未标」是假缺失。
                """
                t = (x.get('atype') or '').strip()
                if t.startswith('陌拜'):
                    return '陌拜'
                if t in ACT_TYPES:
                    return t
                return CH_OF_TYPE.get((x.get('channel') or '').strip(), '未填')

            def _bump(d, lab):
                d[lab] = d.get(lab, 0) + 1

            gtypes = {}
            offline = online = noclass = 0
            cust = {}
            for x in monthly:
                _L = _atype(x)
                if _L == '线下拜访':
                    offline += 1
                elif _L == '线上跟进':
                    online += 1
                elif _L == '未填':
                    noclass += 1
                _bump(gtypes, _L)
                c = (x.get('customer') or '').strip() or '(未填客户)'
                d = cust.setdefault(c, {'customer': c, 'types': {}, 'acts': []})
                _bump(d['types'], _L)
                d['acts'].append({'id': x.get('id', ''), 'date': x.get('date', ''), 'atype': _L,
                                  'type': x.get('type', ''), 'sales': x.get('sales', ''),
                                  'src': x.get('src', '')})
            for d in cust.values():
                d['total'] = sum(d['types'].values())
                d['acts'].sort(key=lambda a: a.get('date') or '', reverse=True)
            # ── 部门 → 销售 → 客户 三级下钻管道 ──
            _dmap = _sales_dept_map()
            _g = {}
            for x in monthly:
                _L = _atype(x)
                _own = (x.get('submitted_by') or '').strip() or (x.get('sales') or '').strip() or '(未知)'
                _dept, _reg = _dmap.get(_own, ('未匹配部门', ''))
                gd = _g.setdefault(_dept, {'dept': _dept, 'types': {}, 'sales': {}})
                _bump(gd['types'], _L)
                gs = gd['sales'].setdefault(_own, {'name': _own, 'dept': _dept, 'region': _reg,
                                                   'types': {}, 'customers': {}})
                _bump(gs['types'], _L)
                _c = (x.get('customer') or '').strip() or '(未填客户)'
                gc = gs['customers'].setdefault(_c, {'customer': _c, 'types': {}, 'acts': []})
                _bump(gc['types'], _L)
                gc['acts'].append({'id': x.get('id', ''), 'date': x.get('date', ''), 'atype': _L,
                                   'type': x.get('type', ''), 'sales': x.get('sales', ''),
                                   'src': x.get('src', '')})
            groups = []
            for gd in _g.values():
                gd['total'] = sum(gd['types'].values())
                _sl = []
                for gs in gd['sales'].values():
                    gs['total'] = sum(gs['types'].values())
                    _cl = list(gs['customers'].values())
                    for gc in _cl:
                        gc['total'] = sum(gc['types'].values())
                        gc['acts'].sort(key=lambda a: a.get('date') or '', reverse=True)
                    _cl.sort(key=lambda d: -d['total'])
                    gs['customers'] = _cl
                    gs['customer_count'] = len(_cl)
                    _sl.append(gs)
                _sl.sort(key=lambda d: -d['total'])
                gd['sales'] = _sl
                gd['sales_count'] = len(_sl)
                groups.append(gd)
            groups.sort(key=lambda d: -d['total'])

            # 近 12 个月趋势（同一权限与 scope 口径，同样按活动类型分桶）
            allm = sorted({(x.get('date') or '')[:7] for x in rows if x.get('date')})
            trend = []
            for m in allm[-12:]:
                mm = [x for x in rows if (x.get('date') or '').startswith(m)]
                _tt = {}
                for x in mm:
                    _bump(_tt, _atype(x))
                trend.append({'month': m, 'types': _tt, 'total': len(mm)})
            self._send_json({'ok': True, 'month': month, 'scope': scope, 'can_team': _allow_team,
                             'type_order': ACT_TYPES, 'types': gtypes,
                             'offline_count': offline, 'online_count': online,
                             'unclassified': noclass, 'total': len(monthly),
                             'customer_count': len(cust), 'months': allm[-12:], 'trend': trend,
                             'departments': groups, 'dept_count': len(groups),
                             'src_breakdown': {
                                 'workbench': len([x for x in monthly if x.get('src') != 'feishu']),
                                 'feishu': len([x for x in monthly if x.get('src') == 'feishu'])},
                             'customers': sorted(cust.values(), key=lambda d: -d['total'])})
            return
'''


def main():
    apply = '--apply' in sys.argv
    s = io.open(F, encoding='utf-8').read()
    print('拜访统计按「活动类型」分桶 —— %s\n' % ('APPLY' if apply else 'DRY-RUN'))
    ok = True
    n = s.count(CONST_ANCHOR)
    print('  %s A 常量 ACT_TYPES/CH_OF_TYPE  命中 %d' % ('✅' if n == 1 else '❌', n))
    if n != 1:
        ok = False
    else:
        s = s.replace(CONST_ANCHOR, CONST_NEW, 1)
    i = s.find(OLD_HEAD)
    j = s.find(OLD_TAIL, i)
    print('  %s B 聚合区间 %s' % ('✅' if (i > 0 and j > i) else '❌',
                                  ('%d 字符' % (j - i)) if (i > 0 and j > i) else '未找到'))
    if i < 0 or j <= i:
        ok = False
    else:
        s = s[:i] + NEW + s[j + len(OLD_TAIL):]
    if not ok:
        print('\n有未命中 → 不落盘')
        return 1
    if apply:
        bak = os.path.join(ROOT, '_bak_p2d_types_%s' % time.strftime('%Y%m%d-%H%M%S'))
        os.makedirs(bak, exist_ok=True)
        shutil.copy2(F, os.path.join(bak, os.path.basename(F)))
        io.open(F, 'w', encoding='utf-8').write(s)
        print('\n  已写（备份 %s）' % bak)
    else:
        print('\n  干跑通过。')
    return 0


sys.exit(main())
