#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""销售管理后台 · 超管只读/编辑接口。

权限：仅刘新元。数据底座：
  数据/customer_rollup_v2.json   真实商机 + 飞书活动回填
  数据/opportunity_status.json   商机系统状态/进度覆盖层
  数据/mcp_customers.json        客户主数据（只读）
不写飞书，不改原始回填数据；所有编辑写覆盖层并追加审计。
"""
import json
import os
import time
from datetime import datetime

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA = os.path.join(ROOT, '数据')
ROLLUP = os.path.join(DATA, 'customer_rollup_v2.json')
STATUS = os.path.join(DATA, 'opportunity_status.json')
AUDIT = os.path.join(DATA, 'admin_audit.jsonl')
STATUSES = ['沟通需求确认', '产品试用中', '订单签订中', '实现销售']
SCENES = ['三类证注册', '动保', '科研客户', '其他']
STAGES = ['陌生开发', '方案匹配', '中试', '临床试验', '已确认被用于注册', '已转产', '客户已获证', '新证迭代']
NODE_STATES = ['未开始', '进行中', '已完成', '卡住']


def _load_json(path, default):
    try:
        with open(path, encoding='utf-8') as f:
            return json.load(f)
    except Exception:
        return default


def _save_json(path, data):
    tmp = path + '.tmp'
    with open(tmp, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    os.replace(tmp, path)


def _statuses():
    d = _load_json(STATUS, {})
    return d.get('items') or {}


def _save_statuses(items):
    _save_json(STATUS, {'updated': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'items': items})


def _key(cust, opp):
    return (cust or '') + '||' + (opp or '')


def _audit(au, action, key, changes):
    try:
        with open(AUDIT, 'a', encoding='utf-8') as f:
            f.write(json.dumps({'at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                                'by': au.get('name') or '', 'action': action,
                                'key': key, 'changes': changes}, ensure_ascii=False) + '\n')
    except Exception:
        pass


def _allowed(au):
    return (au or {}).get('name') == '刘新元' or (au or {}).get('role') == 'admin'


def _enrich(project, items):
    key = _key(project.get('cust'), project.get('opp'))
    it = items.get(key) or {}
    p = dict(project)
    p['key'] = key
    p['system_status'] = it.get('status') or ''
    p['stage'] = it.get('stage') or ''
    p['node_state'] = it.get('node_state') or ''
    p['node_start'] = it.get('node_start') or ''
    p['node_end'] = it.get('node_end') or ''
    p['admin_amount'] = it.get('amount') or ''
    p['admin_scene'] = it.get('scene') or p.get('scene') or ''
    p['admin_sales'] = it.get('sales') or p.get('sales') or ''
    p['admin_note'] = it.get('note') or ''
    p['updated_at'] = it.get('updated_at') or ''
    p['updated_by'] = it.get('updated_by') or ''
    return p


def _base():
    d = _load_json(ROLLUP, {})
    return d.get('projects') or [], d.get('activities') or [], d.get('meta') or {}


def handle_get(path, qs, au):
    if not _allowed(au):
        return {'ok': False, 'error': '仅刘新元可访问管理后台'}
    projects, acts, meta = _base()
    items = _statuses()

    if path == '/api/admin/overview':
        from collections import Counter
        sc = Counter((_enrich(p, items).get('system_status') or '未初始化') for p in projects)
        stc = Counter((_enrich(p, items).get('stage') or '未初始化') for p in projects)
        rawc = Counter((p.get('raw_status') or '未填') for p in projects)
        return {'ok': True, 'data': {
            'projects': len(projects), 'customers': len({p.get('cust') for p in projects}),
            'activities': len(acts), 'unlinked': sum(1 for a in acts if not a.get('opp_names')),
            'initialized': sum(1 for p in projects if (_enrich(p, items).get('system_status'))),
            'status_counts': dict(sc), 'stage_counts': dict(stc), 'raw_status_counts': dict(rawc),
            'statuses': STATUSES, 'scenes': SCENES, 'stages': STAGES, 'node_states': NODE_STATES,
            'depts': sorted({p.get('dept') for p in projects if p.get('dept')}),
            'generated': meta.get('generated') or '', 'updated': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }}

    if path == '/api/admin/opportunities':
        q = (qs.get('q') or '').strip().lower()
        dept = (qs.get('dept') or '').strip()
        scene = (qs.get('scene') or '').strip()
        status = (qs.get('status') or '').strip()
        stage = (qs.get('stage') or '').strip()
        limit = max(1, min(int(qs.get('limit') or 50), 300))
        offset = max(0, int(qs.get('offset') or 0))
        rows = []
        for p in projects:
            x = _enrich(p, items)
            if dept and x.get('dept') != dept: continue
            if scene and x.get('admin_scene') != scene: continue
            if status and (x.get('system_status') or '未初始化') != status: continue
            if stage and (x.get('stage') or '未初始化') != stage: continue
            if q and q not in ' '.join([x.get('cust') or '', x.get('opp') or '', x.get('sales') or '', x.get('dept') or '']).lower():
                continue
            rows.append(x)
        return {'ok': True, 'total': len(rows), 'items': rows[offset:offset + limit],
                'offset': offset, 'limit': limit}

    if path == '/api/admin/customers':
        q = (qs.get('q') or '').strip().lower()
        m = {}
        for p in projects:
            c = p.get('cust') or ''
            if not c: continue
            if q and q not in c.lower(): continue
            x = m.setdefault(c, {'cust': c, 'dept': p.get('dept') or '', 'sales': p.get('sales') or '',
                                 'cid': p.get('cid') or '', 'opps': 0, 'statuses': {}})
            x['opps'] += 1
            it = _enrich(p, items)
            s = it.get('system_status') or '未初始化'
            x['statuses'][s] = x['statuses'].get(s, 0) + 1
        rows = sorted(m.values(), key=lambda x: (-x['opps'], x['cust']))
        return {'ok': True, 'total': len(rows), 'items': rows[:200]}

    if path == '/api/admin/audit':
        rows = []
        try:
            with open(AUDIT, encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if line:
                        try: rows.append(json.loads(line))
                        except Exception: pass
        except Exception:
            pass
        return {'ok': True, 'items': rows[-100:][::-1]}

    return {'ok': False, 'error': '未知管理接口'}


def handle_post(path, body, au):
    if not _allowed(au):
        return {'ok': False, 'error': '仅刘新元可访问管理后台'}
    projects, acts, meta = _base()
    items = _statuses()

    if path == '/api/admin/opportunity/update':
        cust = (body.get('cust') or '').strip()
        opp = (body.get('opp') or '').strip()
        p = next((x for x in projects if (x.get('cust') or '') == cust and (x.get('opp') or '') == opp), None)
        if not p:
            return {'ok': False, 'error': '未找到该商机'}
        key = _key(cust, opp)
        cur = dict(items.get(key) or {})
        allowed = ['status', 'scene', 'stage', 'node_state', 'node_start', 'node_end', 'amount', 'sales', 'note']
        changes = {}
        for k in allowed:
            if k in body:
                v = body.get(k)
                v = '' if v is None else str(v).strip()
                if k == 'status' and v and v not in STATUSES:
                    return {'ok': False, 'error': '非法商机状态'}
                if k == 'scene' and v and v not in SCENES:
                    return {'ok': False, 'error': '非法项目场景'}
                if k == 'stage' and v and v not in STAGES:
                    return {'ok': False, 'error': '非法进度阶段'}
                if k == 'node_state' and v and v not in NODE_STATES:
                    return {'ok': False, 'error': '非法节点状态'}
                cur[k] = v
                changes[k] = v
        cur['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        cur['updated_by'] = au.get('name') or ''
        if any(cur.get(k) for k in allowed):
            items[key] = cur
        else:
            items.pop(key, None)
        _save_statuses(items)
        _audit(au, 'opportunity.update', key, changes)
        return {'ok': True, 'item': _enrich(p, items)}

    if path == '/api/admin/opportunity/bulk-progress':
        keys = body.get('keys') or []
        stage = (body.get('stage') or '').strip()
        state = (body.get('node_state') or '').strip()
        date = (body.get('node_start') or '').strip()
        if not keys or not stage:
            return {'ok': False, 'error': '请选择商机和进度阶段'}
        if stage not in STAGES:
            return {'ok': False, 'error': '非法进度阶段'}
        if state and state not in NODE_STATES:
            return {'ok': False, 'error': '非法节点状态'}
        if len(keys) > 500:
            return {'ok': False, 'error': '单次最多 500 条'}
        pmap = {_key(p.get('cust'), p.get('opp')): p for p in projects}
        n = 0
        for key in keys:
            if key not in pmap:
                continue
            cur = dict(items.get(key) or {})
            cur['stage'] = stage
            cur['node_state'] = state or '进行中'
            if date:
                cur['node_start'] = date
            cur['updated_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            cur['updated_by'] = au.get('name') or ''
            items[key] = cur
            n += 1
        _save_statuses(items)
        _audit(au, 'opportunity.bulk-progress', ','.join(keys[:20]), {'stage': stage, 'node_state': state, 'node_start': date, 'count': n})
        return {'ok': True, 'updated': n}

    return {'ok': False, 'error': '未知管理接口'}
