#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""刷新本月 KPI 到 kpi_progress.json 并部署。
MQL 拉全月订单(所有货号行,不按单据去重) → get_workitem_brief 查销售员(带缓存) → 汇总 → 部署。
"""
import subprocess, json, time, sys
from datetime import datetime, timezone

MCP_URL = 'https://project.feishu.cn/mcp_server/v1'
MCP_TOKEN = 'm-abfb29e8-3104-434f-9944-8d0bb592f8cd'
PK = '6593cd71471290e3cc6be6e6'
ORDER_TYPE = '662612aea6bb7089fea044ef'
BASE = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
CACHE_PATH = f'{BASE}/数据/order_role_cache.json'
KPI_PATH = f'{BASE}/数据/kpi_progress.json'

def call_mcp(method, args, max_retries=3):
    payload = {'jsonrpc': '2.0', 'method': 'tools/call',
               'params': {'name': method, 'arguments': args}, 'id': 1}
    last_err = None
    for attempt in range(max_retries + 1):
        try:
            cmd = ['curl', '-s', '-X', 'POST', MCP_URL,
                   '-H', 'Content-Type: application/json',
                   '-H', 'X-Mcp-Token: ' + MCP_TOKEN,
                   '-d', json.dumps(payload), '--max-time', '30']
            r = subprocess.run(cmd, capture_output=True, text=True, timeout=35)
            response = json.loads(r.stdout)
        except Exception as e:
            last_err = str(e)
            if attempt < max_retries:
                time.sleep(2); continue
            return {'__error__': last_err}
        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 'error' in response:
            return {'__error__': json.dumps(response['error'], ensure_ascii=False)}
        if attempt < max_retries:
            time.sleep(1)
    return {'__error__': last_err or 'unknown'}

def parse_item(item):
    fields = {}
    for f in item.get('moql_field_list') or []:
        k = f.get('key')
        v = f.get('value')
        if v is None:
            fields[k] = ''
        elif isinstance(v, list):
            if len(v) == 0:
                fields[k] = ''
            elif isinstance(v[0], dict) and 'label' in v[0]:
                fields[k] = v[0]['label']
            else:
                v2 = v[0]
                if 'string_value' in v2: fields[k] = v2['string_value']
                elif 'double_value' in v2: fields[k] = v2['double_value']
                elif 'long_value' in v2: fields[k] = v2['long_value']
                else: fields[k] = str(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] = str(v) if v else ''
    return fields

def parse_items(result):
    items = []
    if not result or not isinstance(result, dict):
        return items
    for gid, gitems in (result.get('data') or {}).items():
        for item in gitems:
            items.append(parse_item(item))
    return items

# ---- Step 1: OFFSET 分页拉取全月订单 ----
month = datetime.now().strftime('%Y-%m')
month_start = month + '-01'
mql_base = (f"SELECT `field_51d592`, `work_item_id`, `name` "
            f"FROM `{PK}`.`{ORDER_TYPE}` WHERE `创建时间` >= '{month_start}'")

all_items = []
seen_wid = set()
total = 0
offset = 0
empty_streak = 0
MAX_PAGES = 200
for page in range(1, MAX_PAGES + 1):
    mql = f"{mql_base} LIMIT 50 OFFSET {offset}"
    result = call_mcp('search_by_mql', {'project_key': PK, 'mql': mql})
    if '__error__' in result:
        print(f"ERROR MQL page {page}: {result['__error__']}", file=sys.stderr)
        sys.exit(1)
    # 首页读 total
    if page == 1 and result.get('list'):
        total = result['list'][0].get('count', 0)
    items = parse_items(result)
    if len(items) == 0:
        empty_streak += 1
        if empty_streak >= 2:
            break
        offset += 50
        continue
    empty_streak = 0
    new_count = 0
    for it in items:
        wid = str(it.get('work_item_id', ''))
        if wid and wid in seen_wid:
            continue
        if wid:
            seen_wid.add(wid)
        all_items.append(it)
        new_count += 1
    offset += 50
    if total and len(seen_wid) >= total and len(items) < 50:
        break

print(f"[Step1] 拉取完成: {len(all_items)} 行(货号), 唯一 work_item_id {len(seen_wid)}, MCP total={total}", file=sys.stderr)

# ---- Step 2: 唯一单据编号集合 ----
doc_to_wid = {}
for it in all_items:
    name = it.get('name', '')
    wid = str(it.get('work_item_id', ''))
    if name and name not in doc_to_wid and wid:
        doc_to_wid[name] = wid

print(f"[Step2] 唯一单据编号: {len(doc_to_wid)}", file=sys.stderr)

# ---- Step 3: 查销售员(带缓存) ----
try:
    with open(CACHE_PATH, 'r') as f:
        cache = json.load(f)
except Exception:
    cache = {}

uncached = [d for d in doc_to_wid if d not in cache]
print(f"[Step3] 缓存 {len(cache)} 条, 未命中 {len(uncached)} 条", file=sys.stderr)

for i, doc in enumerate(uncached):
    wid = doc_to_wid[doc]
    result = call_mcp('get_workitem_brief', {
        'project_key': PK,
        'work_item_id': wid,
        'fields': ['role_7dd6e0']
    })
    found = False
    if result and not result.get('__error__') and 'work_item_attribute' in result:
        role_members = result.get('work_item_attribute', {}).get('role_members', []) or []
        for rm in role_members:
            if rm.get('name') == '销售员' or rm.get('key') == 'role_7dd6e0':
                members = rm.get('members', []) or []
                if members:
                    cache[doc] = {'name_cn': members[0].get('name', ''), 'email': members[0].get('email', '')}
                    found = True
                break
    if not found:
        cache[doc] = {'name_cn': '未知', 'email': ''}
    time.sleep(0.12)

with open(CACHE_PATH, 'w') as f:
    json.dump(cache, f, ensure_ascii=False)

# ---- Step 4: 按销售员汇总(所有行累加,不去重) ----
doc_to_sales = {d: (cache.get(d, {}).get('name_cn') or '未知') for d in cache}
by_sales = {}
total_sum = 0.0
for it in all_items:
    doc = it.get('name', '')
    amount = it.get('field_51d592', 0)
    if amount == '' or amount is None:
        amount = 0
    try:
        amount = float(amount)
    except Exception:
        amount = 0
    sp = doc_to_sales.get(doc, '未知')
    by_sales[sp] = by_sales.get(sp, 0.0) + amount
    total_sum += amount

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

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

print(f"[Step4] 写入 {KPI_PATH}: 总行数 {len(all_items)}, 销售员 {len(by_sales)}, 合计 ¥{total_sum:,.2f}", file=sys.stderr)

# ---- Step 5: 部署 ----
deploy_cmd = f"tcb hosting deploy {KPI_PATH} 数据/kpi_progress.json -e bier-sales-d0gatbvlx288724e9"
print(f"[Step5] 部署: {deploy_cmd}", file=sys.stderr)
r = subprocess.run(deploy_cmd, shell=True, capture_output=True, text=True, timeout=120)
deploy_out = (r.stdout or '') + (r.stderr or '')
deploy_ok = (r.returncode == 0)

# ---- 输出 TOP10 + 合计 + 部署结果 ----
print("=" * 60)
print(f"本月 KPI 刷新结果 ({month})")
print("=" * 60)
print(f"合计: ¥{total_sum:,.2f}  |  销售员数: {len(by_sales)}  |  行数: {len(all_items)}  |  单据数: {len(doc_to_wid)}")
print(f"部署: {'✅ 成功' if deploy_ok else '❌ 失败'}")
print("--- TOP10 ---")
rank = 0
for sp, amt in sorted_sales.items():
    rank += 1
    print(f"{rank:2d}. {sp}: ¥{amt:,.2f}")
    if rank >= 10:
        break
print("=" * 60)
if deploy_out.strip():
    print("--- 部署输出 ---")
    print(deploy_out.strip()[-2000:])
