#!/usr/bin/env python3
"""
宝锐工作台数据刷新 — 全量 MCP 拉取脚本
通过 HTTP JSON-RPC 直连飞书 MCP 端点，一次运行完成 4 类数据拉取
"""
import json
import os
import re
import sys
import time
import urllib.request

# ── 配置 ──
MCP_URL = "https://project.feishu.cn/mcp_server/v1"
MCP_TOKEN = "m-abfb29e8-3104-434f-9944-8d0bb592f8cd"
DATA_DIR = "/Users/liuxinyuan/Desktop/Hermes输出-工作类/数据"
SALES_PK = "6593cd71471290e3cc6be6e6"     # 销售管理
AFTERSALES_PK = "658288abfb8bd616b17025f1"  # 售后管理

# 各类型 type_key（HTTP 直连必须用完整 type_key）
TYPE_ACTIVITY = "65ae1e5d44338dbe7c39a29a"  # 活动
TYPE_CUSTOMER = "65ae1e403c87b152f3365ca6"  # 客户
TYPE_ORDER = "662612aea6bb7089fea044ef"     # 销售订单
TYPE_COMPLAINT = "6669433056a98249604376de" # 客诉（售后管理空间）

# ── MCP 调用核心 ──
def mcp_call(method, args, timeout=30):
    payload = {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {"name": method, "arguments": args}
    }
    req = urllib.request.Request(
        MCP_URL,
        data=json.dumps(payload).encode('utf-8'),
        headers={
            "X-Mcp-Token": MCP_TOKEN,
            "Content-Type": "application/json"
        }
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            raw = r.read().decode('utf-8')
    except Exception as e:
        print(f"  ❌ HTTP error: {e}")
        return None

    # 剥离 SSE 包装
    if raw.startswith("data:"):
        raw = raw.split("\n")[0].replace("data: ", "", 1)

    try:
        d = json.loads(raw)
    except Exception as e:
        print(f"  ❌ JSON parse error: {e}, raw[:200]={raw[:200]}")
        return None

    if "error" in d:
        print(f"  ❌ MCP error: {d['error']}")
        return None

    if "result" not in d or "content" not in d["result"]:
        print(f"  ❌ Unexpected response: {json.dumps(d, ensure_ascii=False)[:500]}")
        return None

    # content 数组：第一个是业务 JSON，末尾是 log_id
    for c in d["result"]["content"]:
        t = c.get("text", "")
        if not t:
            continue
        if "log_id" in t:
            continue
        try:
            # 清理尾部 log_id 行
            cleaned = re.sub(r'\nlog_id:.*$', '', t.strip())
            return json.loads(cleaned)
        except Exception:
            pass
    return None


def parse_items(result):
    """解析 MQL search_by_mql 返回的 moql_field_list → 扁平 dict 列表"""
    items = []
    if not result:
        return items
    for gid, gitems in result.get("data", {}).items():
        if not isinstance(gitems, list):
            continue
        for item in gitems:
            fields = {}
            for f in (item.get("moql_field_list") or []):
                k = f["key"]
                v = f.get("value")
                # 数组包裹：[{double_value: 123}]
                if isinstance(v, list) and len(v) > 0:
                    if isinstance(v[0], dict) and "label" in v[0]:
                        fields[k] = v[0]["label"]
                        continue
                    v = v[0]
                if v is None:
                    fields[k] = ""
                elif isinstance(v, dict):
                    if "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"]
                    elif "key_label_value" in v:
                        fields[k] = v["key_label_value"]
                    elif "user_value" in v:
                        fields[k] = v["user_value"]
                    elif "user_value_list" in v:
                        fields[k] = v["user_value_list"]
                    elif "key_label_value_list" in v:
                        fields[k] = v["key_label_value_list"]
                    else:
                        fields[k] = str(v)
                else:
                    fields[k] = str(v)
            items.append(fields)
    return items


def pull_mql_all(pk, mql, limit=2000):
    """翻页拉全量 MQL 结果"""
    all_items = []
    # 首页
    print(f"  首页 MQL...")
    result = mcp_call("search_by_mql", {
        "project_key": pk,
        "mql": mql,
        "session_id": ""
    }, timeout=60)
    if not result:
        print("  ❌ 首页失败")
        return all_items

    items = parse_items(result)
    all_items.extend(items)
    total = 0
    if result.get("list"):
        total = result["list"][0].get("count", 0)
    print(f"  首页: {len(items)} 条, 总数: {total}")

    session_id = result.get("session_id", "")
    if not session_id:
        print("  ⚠️ 无 session_id，无法翻页")
        return all_items

    # 翻页
    page = 2
    while len(all_items) < total and (len(all_items) < limit or limit == 0):
        if len(items) < 50:  # 末页
            break
        result = mcp_call("search_by_mql", {
            "project_key": pk,
            "mql": "",
            "session_id": session_id,
            "group_pagination_list": [{"page_num": page, "group_id": "1"}]
        }, timeout=60)
        if not result:
            print(f"  ⚠️ 第{page}页失败，中断")
            break
        items = parse_items(result)
        if not items:
            break
        all_items.extend(items)
        print(f"  第{page}页: {len(items)} 条, 累计: {len(all_items)}/{total}")
        page += 1
        if page > 40:  # 安全上限 2000 条
            break
    return all_items


def write_json(filepath, data):
    os.makedirs(os.path.dirname(filepath), exist_ok=True)
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    size = os.path.getsize(filepath)
    print(f"  ✅ {os.path.basename(filepath)}: {len(data.get('items', data.get('customers', [])))} 条, {size/1024:.1f}KB")


# ═══════════════════════════════════════════
# Step 1: 客诉数据（改用售后管理空间的正规客诉查询）
# ═══════════════════════════════════════════
print("\n" + "="*60)
print("Step 1: MCP 客诉数据 → mcp_complaints.json")
print("="*60)
# 用户指定查询销售管理.活动，但技能文档明确指出客诉在售后管理空间
# 同时按用户要求拉取售后管理空间的客诉数据
try:
    mql_complaints = (
        "SELECT name, start_time, owner, current_status_operator, "
        "work_item_status, field_9e2144, field_3ce9fe, work_item_id "
        "FROM `售后管理`.`6669433056a98249604376de` "
        "ORDER BY start_time DESC LIMIT 50"
    )
    complaints = pull_mql_all(AFTERSALES_PK, mql_complaints, limit=2000)

    # 格式化输出
    now = time.strftime("%Y-%m-%d %H:%M:%S")
    # 展平 key_label_value 对象，提取 operator 为数组
    output_items = []
    for c in complaints:
        item = dict(c)
        # 处理 current_status_operator
        ops = item.get("current_status_operator", "")
        if isinstance(ops, dict) and "label" in ops:
            item["operator"] = [{"name_cn": ops["label"]}]
        elif isinstance(ops, list):
            item["operator"] = [{"name_cn": o.get("label", o.get("name_cn", str(o)))} for o in ops]
        elif isinstance(ops, str) and ops:
            item["operator"] = [{"name_cn": ops}]
        else:
            item["operator"] = []

        # 计算天数
        st = item.get("start_time", "")
        if st:
            try:
                from datetime import datetime
                dt = datetime.fromisoformat(st.replace("Z", "+00:00"))
                item["days"] = (datetime.now() - dt.replace(tzinfo=None)).days
            except:
                item["days"] = 0

        # status
        ws = item.get("work_item_status", "")
        if isinstance(ws, dict):
            item["status"] = ws.get("label", "")
        output_items.append(item)

    write_json(
        os.path.join(DATA_DIR, "mcp_complaints.json"),
        {"updated": now, "total": len(output_items), "items": output_items}
    )
except Exception as e:
    print(f"  ❌ Step 1 失败: {e}")
    import traceback
    traceback.print_exc()


# ═══════════════════════════════════════════
# Step 2: MCP 客户数据
# ═══════════════════════════════════════════
print("\n" + "="*60)
print("Step 2: MCP 客户数据 → mcp_customers.json")
print("="*60)
try:
    mql_customers = (
        "SELECT name, field_c3224b, field_5ed7ab, field_c8e80d, "
        "field_17186c, field_6415cf, work_item_id "
        "FROM `销售管理`.`65ae1e403c87b152f3365ca6` "
        "ORDER BY name LIMIT 50"
    )
    customers = pull_mql_all(SALES_PK, mql_customers, limit=2000)

    now = time.strftime("%Y-%m-%d %H:%M:%S")
    write_json(
        os.path.join(DATA_DIR, "mcp_customers.json"),
        {"updated_at": now, "customers": customers}
    )
except Exception as e:
    print(f"  ❌ Step 2 失败: {e}")
    import traceback
    traceback.print_exc()


# ═══════════════════════════════════════════
# Step 3: MCP 活动数据（近30天）
# ═══════════════════════════════════════════
print("\n" + "="*60)
print("Step 3: MCP 活动数据 → daily_activities_mcp.json")
print("="*60)
try:
    mql_activities = (
        "SELECT name, start_time, field_b99055, field_5f20fc, owner, work_item_id "
        "FROM `销售管理`.`65ae1e5d44338dbe7c39a29a` "
        "WHERE start_time >= '2026-07-01' "
        "ORDER BY start_time DESC LIMIT 50"
    )
    activities = pull_mql_all(SALES_PK, mql_activities, limit=2000)

    now = time.strftime("%Y-%m-%d %H:%M:%S")
    write_json(
        os.path.join(DATA_DIR, "daily_activities_mcp.json"),
        {"updated": now, "total": len(activities), "items": activities}
    )
except Exception as e:
    print(f"  ❌ Step 3 失败: {e}")
    import traceback
    traceback.print_exc()


# ═══════════════════════════════════════════
# Step 4: MCP 订单数据（本月 8月）
# ═══════════════════════════════════════════
print("\n" + "="*60)
print("Step 4: MCP 订单数据 → mcp_orders_input.json")
print("="*60)
try:
    mql_orders = (
        "SELECT name, `创建时间`, `field_51d592`, work_item_id "
        "FROM `销售管理`.`662612aea6bb7089fea044ef` "
        "WHERE `创建时间` >= '2026-08-01' "
        "ORDER BY `创建时间` DESC LIMIT 50"
    )
    orders = pull_mql_all(SALES_PK, mql_orders, limit=2000)

    # 按单据编号去重（同一订单号多行product）
    seen = set()
    unique_orders = []
    for o in orders:
        oid = o.get("name", "")
        if oid in seen:
            continue
        seen.add(oid)
        unique_orders.append(o)

    now = time.strftime("%Y-%m-%d %H:%M:%S")
    write_json(
        os.path.join(DATA_DIR, "mcp_orders_input.json"),
        {"updated": now, "total": len(unique_orders), "items": unique_orders}
    )
    print(f"  去重: {len(orders)} → {len(unique_orders)} (按单据编号)")
except Exception as e:
    print(f"  ❌ Step 4 失败: {e}")
    import traceback
    traceback.print_exc()

print("\n" + "="*60)
print("全部 MCP 数据拉取完成")
print("="*60)
