#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""本月 KPI 刷新：MQL拉全月订单(不去重) -> 查销售员 -> 按销售员汇总 -> 写 kpi_progress.json -> 部署"""
import subprocess, json, time, os, re, sys
from datetime import datetime, timezone
from collections import defaultdict

MCP_URL = 'https://project.feishu.cn/mcp_server/v1'
PK = '6593cd71471290e3cc6be6e6'
BASE = os.path.expanduser('~/Desktop/Hermes输出-工作类')
CACHE_PATH = os.path.join(BASE, '数据/order_role_cache.json')
KPI_PATH = os.path.join(BASE, '数据/kpi_progress.json')

# 从 config.yaml 读取 token（不硬编码）
cfg_path = os.path.expanduser('~/.hermes/config.yaml')
with open(cfg_path) as f:
    cfg_content = f.read()
m = re.search(r'X-Mcp-Token:\s*(\S+)', cfg_content)
if not m:
    print("[FATAL] token not found in config.yaml"); sys.exit(1)
TOKEN = m.group(1)


def call_mcp(method, args, max_retries=2):
    payload = {'jsonrpc': '2.0', 'method': 'tools/call',
               'params': {'name': method, 'arguments': args}, 'id': 1}
    for attempt in range(max_retries + 1):
        try:
            cmd = ['curl', '-s', '--max-time', '30', '-X', 'POST', MCP_URL,
                   '-H', 'Content-Type: application/json',
                   '-H', 'X-Mcp-Token: ' + TOKEN,
                   '-d', json.dumps(payload)]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=35)
            response = json.loads(result.stdout)
        except Exception:
            if attempt < max_retries:
                time.sleep(2); continue
            return None
        if 'result' in response and 'content' in response['result']:
            for c in response['result']['content']:
                if isinstance(c, dict) and c.get('type') == 'text':
                    try:
                        return json.loads(c['text'])
                    except Exception:
                        pass
        if attempt < max_retries:
            time.sleep(1)
    return None


def parse_item(item):
    fields = {}
    for f in item.get('moql_field_list') or []:
        k = f['key']; v = f.get('value')
        if v is None:
            fields[k] = None
        elif isinstance(v, list):
            if len(v) == 0:
                fields[k] = None
            else:
                v2 = v[0]
                if isinstance(v2, dict):
                    fields[k] = v2.get('double_value') or v2.get('long_value') or v2.get('string_value') or v2.get('label')
                else:
                    fields[k] = v2
        elif 'string_value' in v:
            fields[k] = v['string_value']
        elif 'double_value' in v:
            fields[k] = v['double_value']
        elif 'long_value' in v:
            fields[k] = v['long_value']
        else:
            fields[k] = None
    return fields


# ===== Step 1: OFFSET 翻页拉全月订单（不去重，保留所有行） =====
month_start = datetime.now().strftime('%Y-%m-01')
month_label = datetime.now().strftime('%Y-%m')
mql_base = f"SELECT `name`, `work_item_id`, `field_51d592` FROM `销售管理`.`销售订单` WHERE `创建时间` >= '{month_start}'"

all_rows = []
offset = 0
empty_streak = 0
max_pages = 40
total = None

for page in range(1, max_pages + 1):
    mql = f"{mql_base} LIMIT 50 OFFSET {offset}"
    data = call_mcp('search_by_mql', {'project_key': PK, 'mql': mql})
    if data is None:
        print(f"[ERR] page {page} MQL 调用失败，停止拉取"); break
    if page == 1 and data.get('list'):
        total = data['list'][0]['count']
        print(f"[MQL] 本月订单总记录数: {total}")
    items = [parse_item(it) for _, gitems in (data.get('data') or {}).items() for it in gitems]
    if len(items) == 0:
        empty_streak += 1
        if empty_streak >= 2:
            break
    else:
        empty_streak = 0
    for it in items:
        name = it.get('name') or ''
        wid = str(it.get('work_item_id') or '')
        amt_raw = it.get('field_51d592')
        amt = float(amt_raw) if amt_raw is not None else 0.0
        all_rows.append((name, wid, amt))
    offset += 50
    time.sleep(0.15)

print(f"[MQL] 拉取完成: {len(all_rows)} 行记录")

# ===== Step 2: 提取唯一单据编号 -> work_item_id =====
doc_to_wid = {}
for name, wid, amt in all_rows:
    if name and name not in doc_to_wid and wid:
        doc_to_wid[name] = wid
unique_docs = list(doc_to_wid.keys())
print(f"[DOC] 唯一单据编号: {len(unique_docs)} 个")

# ===== Step 3: 加载缓存，查未缓存的销售员 =====
if os.path.exists(CACHE_PATH):
    with open(CACHE_PATH) as f:
        cache = json.load(f)
else:
    cache = {}
print(f"[CACHE] 已有缓存: {len(cache)} 条")

uncached = [d for d in unique_docs if d not in cache]
print(f"[CACHE] 需查询销售员: {len(uncached)} 个")

new_count = 0
for i, doc in enumerate(uncached):
    wid = doc_to_wid[doc]
    data = call_mcp('get_workitem_brief', {
        'project_key': PK,
        'work_item_id': wid,
        'fields': ['role_7dd6e0']
    })
    sp = None
    if data and 'work_item_attribute' in data:
        role_members = data['work_item_attribute'].get('role_members') or []
        for rm in role_members:
            if rm.get('key') == 'role_7dd6e0' or rm.get('name') == '销售员':
                members = rm.get('members') or []
                if members:
                    sp = members[0].get('name')
                    break
    if sp:
        cache[doc] = {'name_cn': sp, 'email': ''}
        new_count += 1
    else:
        cache[doc] = {'name_cn': '未知', 'email': ''}
    time.sleep(0.12)
    if (i + 1) % 20 == 0:
        print(f"  进度 {i+1}/{len(uncached)}")

with open(CACHE_PATH, 'w') as f:
    json.dump(cache, f, ensure_ascii=False)
print(f"[CACHE] 新增 {new_count} 条，缓存总数 {len(cache)}")

# ===== Step 4: 按销售员汇总（所有行累加，不去重） =====
by_sales = defaultdict(float)
for name, wid, amt in all_rows:
    sp = cache.get(name, {}).get('name_cn', '未知') if name else '未知'
    by_sales[sp] += amt

total_amt = round(sum(by_sales.values()), 2)
by_sales_rounded = {k: round(v, 2) for k, v in by_sales.items()}
sorted_sales = dict(sorted(by_sales_rounded.items(), key=lambda x: x[1], reverse=True))

# 校验
assert abs(sum(sorted_sales.values()) - total_amt) < 0.05, "汇总校验失败"

kpi = {
    'updated_at': datetime.now(timezone.utc).isoformat(),
    'month': month_label,
    'total': total_amt,
    'by_salesperson': sorted_sales
}
with open(KPI_PATH, 'w') as f:
    json.dump(kpi, f, ensure_ascii=False, indent=2)

print(f"[KPI] 写入完成: 合计 ¥{total_amt:,.2f}，{len(sorted_sales)} 名销售员")
print(f"[TOP10]")
for rank, (sp, amt) in enumerate(list(sorted_sales.items())[:10], 1):
    print(f"  {rank:>2}. {sp}: ¥{amt:,.2f}")

# ===== Step 5: 部署 =====
deploy_cmd = f"tcb hosting deploy {KPI_PATH} 数据/kpi_progress.json -e bier-sales-d0gatbvlx288724e9"
print(f"\n[DEPLOY] {deploy_cmd}")
r = subprocess.run(deploy_cmd, shell=True, capture_output=True, text=True, timeout=90)
print(r.stdout)
if r.returncode != 0:
    print(f"[DEPLOY FAILED] {r.stderr}")
    sys.exit(1)
print("[DEPLOY] OK")
