"""
GitCode MCP服务器,提供GitCode API功能的MCP接口
"""
import json
import logging
import os
import sys
from typing import Optional

from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP

from gitcode_mcp.api.base.client import GitCodeAPI

# 配置日志
# 注意:MCP服务器使用stdio通信,stdout只能用于JSON-RPC消息
# 日志必须输出到stderr或文件,否则会导致协议解析错误
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stderr),  # 输出到标准错误流
        logging.FileHandler("gitcode_mcp.log")
    ]
)
logger = logging.getLogger("gitcode_mcp")
logger.info("GitCode MCP服务器模块初始化...")

# 加载环境变量
load_dotenv()
logger.info("环境变量已加载")

# 创建FastMCP服务器实例
mcp = FastMCP("GitCode MCP服务器")
logger.info(f"FastMCP实例已创建,名称: GitCode MCP服务器")
api_client: Optional[GitCodeAPI] = None


# 初始化API客户端
def init_api_client():
    """初始化API客户端"""
    global api_client
    if api_client is not None:
        return api_client
        
    token = os.environ.get("GITCODE_TOKEN")
    if not token:
        logger.warning("未设置GITCODE_TOKEN环境变量,API访问可能受限")
    
    # 从环境变量读取代理配置
    proxy = os.environ.get("HTTP_PROXY") or os.environ.get("HTTPS_PROXY")
    if proxy:
        logger.info(f"检测到代理配置: {proxy}")
    
    api_client = GitCodeAPI(token=token, proxy=proxy)
    logger.info("GitCode API客户端已初始化")
    return api_client


# 辅助函数
async def safe_api_call(func, *args, **kwargs):
    """安全调用API,统一处理错误和日志"""
    client = init_api_client()
    
    try:
        return await func(*args, **kwargs)
    except Exception as e:
        error_message = f"API调用失败: {func.__name__}({args}, {kwargs}) - {str(e)}"
        logger.error(error_message)
        raise ValueError(error_message) from e


# === 工具 ===

@mcp.tool()
async def list_repositories() -> str:
    """列出当前用户的仓库"""
    client = init_api_client()
    repos = await safe_api_call(client.repos.list_user_repos)
    return json.dumps(repos, ensure_ascii=False)


@mcp.tool()
async def get_repository(owner: str, repo: str) -> str:
    """获取特定仓库的详细信息"""
    client = init_api_client()
    repo_info = await safe_api_call(client.repos.get_repo, owner=owner, repo=repo)
    return json.dumps(repo_info, ensure_ascii=False)


@mcp.tool()
async def create_repository(name: str, description: str = "", private: bool = False) -> str:
    """创建新仓库"""
    client = init_api_client()
    repo = await safe_api_call(client.repos.create_repo, name=name, description=description, private=private)
    return json.dumps(repo, ensure_ascii=False)


@mcp.tool()
async def list_branches(owner: str, repo: str) -> str:
    """列出仓库的分支"""
    client = init_api_client()
    branches = await safe_api_call(client.branches.list_branches, owner=owner, repo=repo)
    return json.dumps(branches, ensure_ascii=False)


@mcp.tool()
async def get_branch(owner: str, repo: str, branch: str) -> str:
    """获取特定分支的详细信息"""
    client = init_api_client()
    branch_info = await safe_api_call(client.branches.get_branch, owner=owner, repo=repo, branch=branch)
    return json.dumps(branch_info, ensure_ascii=False)


@mcp.tool()
async def create_branch(owner: str, repo: str, branch: str, ref: str) -> str:
    """创建新分支"""
    client = init_api_client()
    branch_info = await safe_api_call(client.branches.create_branch, owner=owner, repo=repo, branch=branch, ref=ref)
    return json.dumps(branch_info, ensure_ascii=False)


@mcp.tool()
async def list_issues(owner: str, repo: str) -> str:
    """列出仓库的Issues"""
    client = init_api_client()
    issues = await safe_api_call(client.issues.list_issues, owner=owner, repo=repo)
    return json.dumps(issues, ensure_ascii=False)


@mcp.tool()
async def get_issue(owner: str, repo: str, issue_number: int) -> str:
    """获取特定Issue的详细信息"""
    client = init_api_client()
    issue = await safe_api_call(client.issues.get_issue, owner=owner, repo=repo, issue_number=issue_number)
    return json.dumps(issue, ensure_ascii=False)


@mcp.tool()
async def create_issue(owner: str, repo: str, title: str, body: str = "") -> str:
    """创建新Issue"""
    client = init_api_client()
    issue = await safe_api_call(client.issues.create_issue, owner=owner, repo=repo, title=title, body=body)
    return json.dumps(issue, ensure_ascii=False)


@mcp.tool()
async def list_issue_comments(owner: str, repo: str, issue_number: int) -> str:
    """列出Issue的评论列表"""
    client = init_api_client()
    comments = await safe_api_call(
        client.issues.list_comments,
        owner=owner,
        repo=repo,
        issue_number=issue_number
    )
    return json.dumps(comments, ensure_ascii=False)


@mcp.tool()
async def create_issue_comment(owner: str, repo: str, issue_number: int, body: str) -> str:
    """创建Issue评论"""
    client = init_api_client()
    comment = await safe_api_call(
        client.issues.add_comment,
        owner=owner,
        repo=repo,
        issue_number=issue_number,
        body=body
    )
    return json.dumps(comment, ensure_ascii=False)


@mcp.tool()
async def list_pull_requests(owner: str, repo: str) -> str:
    """列出仓库的Pull Requests"""
    client = init_api_client()
    prs = await safe_api_call(client.pulls.list_pull_requests, owner=owner, repo=repo)
    return json.dumps(prs, ensure_ascii=False)


@mcp.tool()
async def get_pull_request(owner: str, repo: str, pull_number: int) -> str:
    """获取特定Pull Request的详细信息"""
    client = init_api_client()
    pr = await safe_api_call(client.pulls.get_pull_request, owner=owner, repo=repo, pr_number=pull_number)
    return json.dumps(pr, ensure_ascii=False)


@mcp.tool()
async def create_pull_request(owner: str, repo: str, title: str, head: str, base: str, body: str = "") -> str:
    """创建新Pull Request"""
    client = init_api_client()
    pr = await safe_api_call(
        client.pulls.create_pull_request, 
        owner=owner, 
        repo=repo, 
        title=title, 
        head=head, 
        base=base, 
        body=body
    )
    return json.dumps(pr, ensure_ascii=False)


@mcp.tool()
async def update_pull_request(owner: str, repo: str, pull_number: int, title: str = None, body: str = None, state: str = None) -> str:
    """更新Pull Request"""
    client = init_api_client()
    pr = await safe_api_call(
        client.pulls.update_pull_request,
        owner=owner,
        repo=repo,
        pr_number=pull_number,
        title=title,
        body=body,
        state=state
    )
    return json.dumps(pr, ensure_ascii=False)


@mcp.tool()
async def merge_pull_request(owner: str, repo: str, pull_number: int, commit_title: str = None, commit_message: str = None, merge_method: str = None) -> str:
    """合并Pull Request"""
    client = init_api_client()
    result = await safe_api_call(
        client.pulls.merge_pull_request,
        owner=owner,
        repo=repo,
        pr_number=pull_number,
        commit_title=commit_title,
        commit_message=commit_message,
        merge_method=merge_method
    )
    return json.dumps(result, ensure_ascii=False)


@mcp.tool()
async def list_pull_request_comments(
    owner: str,
    repo: str,
    pull_number: int,
    direction: str = None,
    comment_type: str = None,
) -> str:
    """列出Pull Request的评论列表。

    direction: 可选,排序方向,asc 升序 或 desc 降序。
    comment_type: 可选,筛选评论类型:diff_comment(代码行/diff 评论)、pr_comment(PR 普通评论)。
    """
    client = init_api_client()
    comments = await safe_api_call(
        client.pulls.list_pull_request_comments,
        owner=owner,
        repo=repo,
        pr_number=pull_number,
        direction=direction,
        comment_type=comment_type,
    )
    return json.dumps(comments, ensure_ascii=False)


@mcp.tool()
async def create_pull_request_comment(owner: str, repo: str, pull_number: int, body: str, path: str = None, position: int = None) -> str:
    """在Pull Request添加评论(可选path和position用于代码行评论)"""
    client = init_api_client()
    comment = await safe_api_call(
        client.pulls.create_pull_request_comment,
        owner=owner,
        repo=repo,
        pr_number=pull_number,
        body=body,
        path=path,
        position=position
    )
    return json.dumps(comment, ensure_ascii=False)


@mcp.tool()
async def get_pull_request_comment(owner: str, repo: str, comment_id: int) -> str:
    """获取 Pull Request 单条评论详情(含 discussion_id 等字段,便于回复讨论线程)。"""
    client = init_api_client()
    comment = await safe_api_call(
        client.pulls.get_pull_request_comment,
        owner=owner,
        repo=repo,
        comment_id=comment_id,
    )
    return json.dumps(comment, ensure_ascii=False)


@mcp.tool()
async def reply_to_pull_request_comment(
    owner: str,
    repo: str,
    pull_number: int,
    discussion_id: str,
    body: str,
) -> str:
    """在指定 PR 的讨论线程下回复评论(discussion_id 可由 get_pull_request_comment 等接口获得)。"""
    client = init_api_client()
    result = await safe_api_call(
        client.pulls.reply_to_pull_request_comment,
        owner=owner,
        repo=repo,
        pr_number=pull_number,
        discussion_id=discussion_id,
        body=body,
    )
    return json.dumps(result, ensure_ascii=False)


# === 搜索功能 ===
# 注意:以下搜索功能暂时注释,因为平台目前不支持

# @mcp.tool()
# async def search_code(query: str) -> str:
#     """搜索代码"""
#     client = init_api_client()
#     results = await safe_api_call(client.search.search_code, query=query)
#     return json.dumps(results, ensure_ascii=False)

@mcp.tool()
async def search_repositories(query: str) -> str:
    """搜索仓库"""
    client = init_api_client()
    results = await safe_api_call(client.search.search_repositories, query=query)
    return json.dumps(results, ensure_ascii=False)


@mcp.tool()
async def search_issues(query: str) -> str:
    """搜索Issues"""
    client = init_api_client()
    results = await safe_api_call(client.search.search_issues, query=query)
    return json.dumps(results, ensure_ascii=False)


@mcp.tool()
async def search_users(query: str) -> str:
    """搜索用户"""
    client = init_api_client()
    results = await safe_api_call(client.search.search_users, query=query)
    return json.dumps(results, ensure_ascii=False)


# === 资源 ===

@mcp.resource("repo://{owner}/{name}")
async def get_repository_resource(owner: str, name: str) -> str:
    """获取仓库资源"""
    client = init_api_client()
    
    try:
        repo_data = await safe_api_call(client.repos.get_repo, owner=owner, repo=name)
        formatted_content = (
            f"# {repo_data.get('name')}\n\n"
            f"{repo_data.get('description', '')}\n\n"
            f"- 所有者: {owner}\n"
            f"- 星标数: {repo_data.get('stargazers_count', 0)}\n"
            f"- Fork数: {repo_data.get('forks_count', 0)}\n"
            f"- 默认分支: {repo_data.get('default_branch', 'main')}\n"
            f"- 创建时间: {repo_data.get('created_at', '')}\n"
            f"- 最后更新: {repo_data.get('updated_at', '')}\n"
        )
        
        return formatted_content
    except Exception as e:
        logger.error(f"读取资源时出错: {owner}/{name} - {e}")
        return f"Error: {str(e)}"


# === 提示模板 ===

@mcp.prompt()
def create_issue_prompt(owner: str, repo: str, title: str, body: str = "") -> str:
    """创建Issue的提示模板"""
    return f"""在 {owner}/{repo} 仓库中创建一个新Issue:

标题:{title}

内容:{body}"""


@mcp.prompt()
def create_pull_request_prompt(owner: str, repo: str, title: str, head: str, base: str, body: str = "") -> str:
    """创建Pull Request的提示模板"""
    return f"""在 {owner}/{repo} 仓库中创建一个新Pull Request:

标题:{title}

从分支 {head} 到 {base}

描述:{body}"""


# @mcp.prompt()
# def search_code_prompt(query: str) -> str:
#     """搜索代码的提示模板"""
#     return f"""搜索代码片段:{query}"""


def main():
    """主函数,启动MCP服务器"""
    logger.info("正在启动GitCode MCP服务器...")
    try:
        # 初始化API客户端
        init_api_client()
        logger.info("API客户端已初始化,准备启动服务器...")
        
        # FastMCP.run() 会启动服务器并保持运行
        mcp.run()
    except KeyboardInterrupt:
        logger.info("服务器被用户中断")
    except Exception as e:
        logger.error(f"服务器运行错误: {e}", exc_info=True)
        raise
    finally:
        # 清理资源
        import asyncio
        if api_client:
            try:
                asyncio.run(api_client.close())
                logger.info("API客户端已关闭")
            except Exception as e:
                logger.error(f"关闭API客户端时出错: {e}")


if __name__ == "__main__":
    main()