# -*- coding: utf-8 -*-
"""足球数据 API 的 MCP 服务器 —— 让 AI 客户端（Claude Desktop / Cursor / Cline 等）
直接把接口当"工具"调用，不用写代码。

用法：
    set FOOTBALL_API_KEY=bf_xxxx
    set FOOTBALL_API_BASE=https://zqapi.com.cn
    python mcp_server.py                # stdio（桌面客户端默认）
    python mcp_server.py --http 8765    # HTTP 模式（给网页端 AI 客户端）
    python mcp_server.py --selftest     # 自检：列出工具并试调一个

Claude Desktop 配置（claude_desktop_config.json）：
{
  "mcpServers": {
    "football-data": {
      "command": "python",
      "args": ["C:/路径/mcp_server.py"],
      "env": {"FOOTBALL_API_KEY": "bf_xxxx", "FOOTBALL_API_BASE": "https://zqapi.com.cn"}
    }
  }
}
"""
from __future__ import annotations

import json
import os
import sys

import httpx
from mcp.server.mcpserver import MCPServer

BASE = os.environ.get("FOOTBALL_API_BASE", "https://zqapi.com.cn").rstrip("/")
KEY = os.environ.get("FOOTBALL_API_KEY", "")
TIMEOUT = float(os.environ.get("FOOTBALL_API_TIMEOUT", "60"))

server = MCPServer(
    "football-data",
    instructions=(
        "足球赛事数据。可以查当天赛事、单场详情、阵容、伤停、技术统计(xG)、"
        "多公司赔率、资金占比、球队近况、交锋记录、竞彩与北单场次。"
        "所有数据为客观统计，仅供分析研究，不含投注建议。"
    ),
)


def _get(path: str, params: dict | None = None) -> dict | list:
    if not KEY:
        return {"error": "缺少 FOOTBALL_API_KEY 环境变量，请先在配置里填 API Key"}
    url = BASE + path
    try:
        with httpx.Client(timeout=TIMEOUT, follow_redirects=True) as c:
            r = c.get(url, params=params or {}, headers={"X-API-Key": KEY})
        try:
            body = r.json()
        except ValueError:
            body = {"raw": r.text[:800]}
        if r.status_code >= 400:
            return {"error": body.get("detail") or body, "status": r.status_code}
        return body
    except Exception as exc:  # 网络异常也返回结构化错误，别让 AI 卡住
        return {"error": f"{type(exc).__name__}: {exc}"}


@server.tool(description="查某天的赛事列表（统一视图：含竞彩/北单/bzzoiro 合并）。"
                         "date 用 YYYY-MM-DD，不填=今天；limit 默认 20。")
def list_matches(date: str = "", limit: int = 20) -> dict:
    params = {"limit": limit}
    if date:
        params["date"] = date
    return _get("/v1/matches", params)


@server.tool(description="查单场比赛详情（含球队中英文名、开赛时间、比分、状态、来源）。"
                         "match_id 形如 bz:210131 或 jc:周日019。")
def match_detail(match_id: str) -> dict:
    return _get(f"/v1/matches/{match_id}")


@server.tool(description="查某场比赛的亚盘/欧赔/大小球赔率。match_id 同 match_detail。")
def match_odds(match_id: str) -> dict:
    return _get(f"/v1/matches/{match_id}/odds")


@server.tool(description="查某个赛事（bzzoiro 事件 id）的完整详情：天气、裁判、场地、上座、是否德比等。")
def event_detail(event_id: int) -> dict:
    return _get(f"/v1/bz/events/{event_id}")


@server.tool(description="查某场比赛的预测/官方首发阵容（阵型、球员位置、评分）。")
def lineups(event_id: int) -> dict:
    return _get(f"/v1/bz/events/{event_id}/lineups")


@server.tool(description="查某场比赛的伤停名单（伤病/停赛/出战成疑 + 原因）。")
def injuries(event_id: int) -> dict:
    return _get(f"/v1/bz/events/{event_id}/injuries")


@server.tool(description="查某场比赛的技术统计：xG、控球、射门、角球、传球成功率等 50+ 项。")
def stats(event_id: int) -> dict:
    return _get(f"/v1/bz/events/{event_id}/stats")


@server.tool(description="查某场比赛的多公司赔率（13 家），含初盘、即时、隐含概率、变动方向。")
def odds(event_id: int) -> dict:
    return _get(f"/v1/bz/events/{event_id}/odds")


@server.tool(description="查某场比赛的资金占比（WoM）：总成交额、每个选项成交量与占比、联赛平均成交额。")
def money_share(event_id: int) -> dict:
    return _get(f"/v1/wom/events/{event_id}")


@server.tool(description="查某支球队近 10 场战绩（含赢盘率）。team 用中文名，如 国际米兰。")
def team_form(team: str, last: int = 10) -> dict:
    return _get(f"/v1/teams/{team}/form", {"last": last})


@server.tool(description="查两队历史交锋记录。home / away 用中文队名。")
def head_to_head(home: str, away: str, last: int = 10) -> dict:
    return _get("/v1/h2h", {"home": home, "away": away, "last": last})


@server.tool(description="查当天竞彩场次（含编号、固定奖金）。需专业版及以上。")
def jingcai(date: str = "") -> dict:
    params = {"date": date} if date else {}
    return _get("/v1/jc/matches", params)


@server.tool(description="查当天北单场次（含编号、让球、SP）。需专业版及以上。")
def beidan(date: str = "") -> dict:
    params = {"date": date} if date else {}
    return _get("/v1/bjdc/matches", params)


@server.tool(description="查我的套餐、今日用量与剩余额度。")
def my_quota() -> dict:
    return _get("/v1/me")


def selftest() -> int:
    print(f"BASE={BASE}  KEY={'已设置' if KEY else '未设置'}")
    tools = server.list_tools_sync() if hasattr(server, "list_tools_sync") else None
    if tools is None:
        try:
            import asyncio
            tools = asyncio.run(server.list_tools())
        except Exception as exc:
            print("列工具失败:", exc)
            tools = []
    print("工具数:", len(tools))
    for t in tools:
        print("  -", getattr(t, "name", t))
    print("\n试调 list_matches(limit=2):")
    print(json.dumps(list_matches(limit=2), ensure_ascii=False)[:600])
    return 0


if __name__ == "__main__":
    args = sys.argv[1:]
    if "--selftest" in args:
        raise SystemExit(selftest())
    if "--http" in args:
        port = int(args[args.index("--http") + 1]) if len(args) > args.index("--http") + 1 else 8765
        server.run(transport="streamable-http", port=port)
    else:
        server.run(transport="stdio")
