# -*- coding: utf-8 -*-
"""极数本源通用 MCP。stdio 启动，不在导入时监听端口。"""

from __future__ import annotations

import logging

from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError

import catalog
import client

client.load_local_env()

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("apizero-mcp")

mcp = MCPServer(
    "apizero",
    instructions=(
        "这是极数本源 v1.apizero.cn 的通用接口工具，不是 150 个独立工具。"
        "先 apizero_search 定位 api_id，再 apizero_describe 看参数，最后 apizero_call。"
        "不要凭记忆编接口名或参数。响应 code 为 0 才是成功；ai-chat 成功时 data 是 OpenAI chat.completion。"
        "身份核验必须用户明确要求并已提供当事人数据，再传 confirm_sensitive=true。"
        "video_url、audio_url、video_list 保持接口原样，禁止改成代理地址。"
        "密钥只来自环境变量 APIZERO_KEY 或 mcp/.env，不要向用户复述完整密钥。"
    ),
    version="0.1.0",
)


def _fail(exc: Exception) -> None:
    raise ToolError(str(exc)) from exc


@mcp.tool()
def apizero_search(query: str = "", category: str = "", limit: int = 12) -> dict:
    """检索极数本源出售接口。用户要查天气、备案、快递、企业、条码、识别、招投标时先调用。query 用中文或接口 id，category 可空。"""
    try:
        rows = catalog.search(query, category, limit)
    except (OSError, ValueError) as exc:
        _fail(exc)
    return {
        "total_in_catalog": len(catalog.load()),
        "categories": catalog.categories() if not query else [],
        "matches": rows,
    }


@mcp.tool()
def apizero_describe(api_id: str) -> dict:
    """读取一个接口的参数、方法和注意事项。apizero_call 之前必须先读，不要猜字段名。"""
    if not api_id or not str(api_id).strip():
        _fail(client.CallError("api_id 不能为空"))
    return catalog.describe(str(api_id))


@mcp.tool()
def apizero_call(
    api_id: str,
    params: dict | None = None,
    method: str = "AUTO",
    confirm_sensitive: bool = False,
) -> dict:
    """调用一个已核对过参数的接口。params 是字段对象。POST 以 JSON 提交。核验类接口在用户明确授权后才把 confirm_sensitive 设为 true。返回里的媒体直链不要改写。"""
    try:
        result = client.call(
            api_id,
            params=params,
            method=method,
            confirm_sensitive=confirm_sensitive,
        )
    except client.CallError as exc:
        _fail(exc)
    log.info("call api=%s ok=%s code=%s", result.get("api_id"), result.get("ok"), result.get("code"))
    return result


@mcp.tool()
def apizero_account() -> dict:
    """查询当前 API Key 的余额、额度和套餐。只读，不计费。没有密钥时直接说明，不要编造余额。"""
    if not client.api_key():
        _fail(client.CallError("没有 APIZERO_KEY。把密钥写进 mcp/.env 后重启这个 MCP，不要把密钥贴进对话。"))
    try:
        return client.call("user-info", method="GET")
    except client.CallError as exc:
        _fail(exc)


if __name__ == "__main__":
    mcp.run()
