"""GitHub MCP-powered tools for enhanced GitHub research.

These tools wrap the GitHub MCP server to provide rich GitHub capabilities
including code search, file content retrieval, and PR analysis with diffs/comments.

Unlike the basic gh CLI tools, these provide:
- Full code search across repositories
- File content reading
- PR diffs and review comments
- Issue tracking and comments

The tools use the GITHUB_REPO environment variable as the default repository
when owner/repo are not explicitly specified.
"""

from typing import Optional

from emdash.agent.tools.base import BaseTool, ToolResult, ToolCategory
from emdash.agent.mcp import GitHubMCPClient, MCPError
from emdash.agent.mcp.client import get_mcp_client
from emdash.core.config import get_config
from emdash.utils.logger import log


class MCPBaseTool(BaseTool):
    """Base class for MCP-powered tools."""

    category = ToolCategory.SEARCH

    def __init__(self, connection=None, mcp_client: Optional[GitHubMCPClient] = None):
        """Initialize the MCP tool.

        Args:
            connection: Neo4j connection (for base tool compatibility)
            mcp_client: Optional MCP client instance. If None, uses global client.
        """
        super().__init__(connection)
        self._mcp_client = mcp_client

    @property
    def mcp_client(self) -> GitHubMCPClient:
        """Get the MCP client, initializing if needed."""
        if self._mcp_client is None:
            self._mcp_client = get_mcp_client()
        return self._mcp_client

    def _get_default_repo(self) -> tuple[Optional[str], Optional[str]]:
        """Get the default owner/repo from GITHUB_REPO config.

        Returns:
            Tuple of (owner, repo) or (None, None) if not configured
        """
        config = get_config()
        return config.mcp.repo_owner, config.mcp.repo_name
    
    def _ensure_repo_context(
        self, 
        owner: Optional[str], 
        repo: Optional[str],
    ) -> tuple[Optional[str], Optional[str], Optional[ToolResult]]:
        """Ensure owner/repo are set, using config defaults.
        
        NEVER allows global GitHub search - always scopes to configured repo.
        
        Args:
            owner: Provided owner (may be None)
            repo: Provided repo (may be None)
            
        Returns:
            Tuple of (owner, repo, error) - error is ToolResult if no repo configured
        """
        if not owner or not repo:
            default_owner, default_repo = self._get_default_repo()
            owner = owner or default_owner
            repo = repo or default_repo
        
        # Fail if no repo - never allow global search
        if not owner or not repo:
            error = ToolResult.error_result(
                "No repository configured. GitHub MCP tools require a repository context. "
                "Set GITHUB_REPO in .env (e.g., 'wix-private/picasso')",
                suggestions=[
                    "Set GITHUB_REPO=owner/repo in your .env file",
                    "Or pass owner and repo parameters explicitly",
                ],
            )
            return None, None, error
        
        return owner, repo, None

    def _ensure_mcp_available(self) -> Optional[ToolResult]:
        """Check if MCP is available and return error result if not.

        Returns:
            ToolResult error if MCP not available, None if available
        """
        if not self.mcp_client.is_available:
            return ToolResult.error_result(
                "GitHub MCP not available. Ensure GITHUB_TOKEN is set and "
                "github-mcp-server binary is installed.",
                suggestions=[
                    "Set GITHUB_TOKEN or GITHUB_PERSONAL_ACCESS_TOKEN env var",
                    "Download github-mcp-server from https://github.com/github/github-mcp-server/releases",
                ],
            )
        return None


class GitHubSearchCodeTool(MCPBaseTool):
    """Search for code in the configured repository."""

    name = "github_search_code"
    description = (
        "Search for code patterns in the configured GitHub repository. "
        "Use this to find implementations, usage examples, or specific code patterns. "
        "Supports GitHub search qualifiers like 'language:typescript'. "
        "ALWAYS searches within the GITHUB_REPO configured in .env."
    )

    def execute(
        self,
        query: str,
        owner: Optional[str] = None,
        repo: Optional[str] = None,
        per_page: int = 10,
    ) -> ToolResult:
        """Search for code on GitHub.

        Args:
            query: Search query (e.g., "useState", "async function login")
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)
            per_page: Number of results (default 10, max 100)

        Returns:
            ToolResult with matching code snippets
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        # ALWAYS use configured repo - never allow global search
        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        try:
            # Start client if needed
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            response = self.mcp_client.search_code(
                query=query,
                owner=owner,
                repo=repo,
                per_page=min(per_page, 100),
            )

            if not response.success:
                return ToolResult.error_result(
                    f"Code search failed: {response.error}",
                    suggestions=["Try a more specific query", "Check repository access"],
                )

            # Parse results - GitHub code search returns {total_count, items}
            result = response.result
            if isinstance(result, dict):
                raw_results = result.get("items", [])
            elif isinstance(result, list):
                raw_results = result
            else:
                raw_results = []

            results = []
            for item in raw_results:
                if isinstance(item, dict):
                    repo_info = item.get("repository", {})
                    results.append({
                        "name": item.get("name", ""),
                        "path": item.get("path", ""),
                        "repository": repo_info.get("full_name", "") if isinstance(repo_info, dict) else str(repo_info),
                        "url": item.get("html_url", ""),
                        "score": item.get("score", 0),
                    })

            suggestions = []
            if results:
                suggestions.append(
                    f"Found {len(results)} results. Use github_get_file_content to read full files."
                )
            else:
                suggestions.append("No results found. Try broader search terms.")

            return ToolResult.success_result(
                data={"results": results, "count": len(results), "query": query},
                suggestions=suggestions,
            )

        except MCPError as e:
            return ToolResult.error_result(
                f"MCP error: {e}",
                suggestions=["Check MCP server status", "Verify GitHub token"],
            )
        except Exception as e:
            log.exception("GitHub search code error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "query": {
                    "type": "string",
                    "description": "Search query (supports GitHub search syntax)",
                },
                "owner": {
                    "type": "string",
                    "description": "Repository owner to scope search (optional)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name to scope search (optional)",
                },
                "per_page": {
                    "type": "integer",
                    "default": 10,
                    "description": "Number of results (max 100)",
                },
            },
            required=["query"],
        )


class GitHubGetFileContentTool(MCPBaseTool):
    """Read file contents from a GitHub repository."""

    name = "github_get_file_content"
    description = (
        "Get the contents of a file from a GitHub repository. "
        "Use this to read source code, configuration files, or documentation "
        "directly from GitHub without cloning the repository. "
        "If owner/repo not specified, uses the configured GITHUB_REPO."
    )

    def execute(
        self,
        path: str,
        owner: Optional[str] = None,
        repo: Optional[str] = None,
        branch: Optional[str] = None,
    ) -> ToolResult:
        """Get file contents from GitHub.

        Args:
            path: File path within the repository (e.g., "src/index.js")
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)
            branch: Optional branch/ref name (defaults to default branch)

        Returns:
            ToolResult with file contents
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        # ALWAYS use configured repo - never allow global operations
        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        if not owner or not repo:
            return ToolResult.error_result(
                "Repository owner and name are required. "
                "Set GITHUB_REPO in .env or provide owner/repo parameters.",
            )

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            response = self.mcp_client.get_file_contents(
                owner=owner,
                repo=repo,
                path=path,
                branch=branch,
            )

            if not response.success:
                return ToolResult.error_result(
                    f"Failed to get file: {response.error}",
                    suggestions=[
                        "Check if the file path is correct",
                        "Verify repository access",
                    ],
                )

            # Handle different response formats
            # MCP returns content blocks, file content may be in 'content', 'text', or as raw string
            content = response.result
            if isinstance(content, list):
                # Content blocks array - extract text from each block
                texts = []
                for block in content:
                    if isinstance(block, dict) and block.get("type") == "text":
                        texts.append(block.get("text", ""))
                    elif isinstance(block, str):
                        texts.append(block)
                file_content = "\n".join(texts)
            elif isinstance(content, dict):
                # May have content or text field
                file_content = content.get("content", content.get("text", ""))
                if not file_content:
                    # Try to find any text in the dict
                    file_content = str(content)
            else:
                file_content = str(content) if content else ""

            # Truncate very long files for tool output
            max_length = 50000
            truncated = False
            if len(file_content) > max_length:
                file_content = file_content[:max_length]
                truncated = True

            suggestions = []
            if truncated:
                suggestions.append("File was truncated. Consider reading specific sections.")

            return ToolResult.success_result(
                data={
                    "content": file_content,
                    "path": path,
                    "repository": f"{owner}/{repo}",
                    "branch": branch or "default",
                    "truncated": truncated,
                },
                suggestions=suggestions,
            )

        except MCPError as e:
            return ToolResult.error_result(
                f"MCP error: {e}",
                suggestions=["Check MCP server status", "Verify GitHub token"],
            )
        except Exception as e:
            log.exception("GitHub get file content error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "path": {
                    "type": "string",
                    "description": "File path within the repository",
                },
                "owner": {
                    "type": "string",
                    "description": "Repository owner (defaults to GITHUB_REPO config)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name (defaults to GITHUB_REPO config)",
                },
                "branch": {
                    "type": "string",
                    "description": "Branch or ref name (optional)",
                },
            },
            required=["path"],
        )


class GitHubPRDetailsTool(MCPBaseTool):
    """Get rich details of a pull request including diff, comments, and reviews."""

    name = "github_pr_details"
    description = (
        "Get detailed information about a pull request including the diff, "
        "comments, reviews, and inline code review comments. Use this for deep PR analysis, "
        "understanding code changes, and reviewing discussion context. "
        "Review comments contain the actual code feedback on specific lines. "
        "If owner/repo not specified, uses the configured GITHUB_REPO."
    )
    category = ToolCategory.HISTORY

    def execute(
        self,
        pull_number: int,
        owner: Optional[str] = None,
        repo: Optional[str] = None,
        include_diff: bool = True,
        include_comments: bool = True,
        include_reviews: bool = True,
        include_review_comments: bool = True,
    ) -> ToolResult:
        """Get PR details with optional diff, comments, and reviews.

        Args:
            pull_number: PR number
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)
            include_diff: Whether to include the PR diff
            include_comments: Whether to include PR issue comments (general discussion)
            include_reviews: Whether to include PR reviews (approve/request changes actions)
            include_review_comments: Whether to include inline code review comments

        Returns:
            ToolResult with PR details
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        # ALWAYS use configured repo - never allow global operations
        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        if not owner or not repo:
            return ToolResult.error_result(
                "Repository owner and name are required. "
                "Set GITHUB_REPO in .env or provide owner/repo parameters.",
            )

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            # Get basic PR info
            pr_response = self.mcp_client.get_pull_request(owner, repo, pull_number)
            if not pr_response.success:
                return ToolResult.error_result(
                    f"Failed to get PR: {pr_response.error}",
                    suggestions=["Check PR number", "Verify repository access"],
                )

            result = {
                "pr": pr_response.result,
                "owner": owner,
                "repo": repo,
                "number": pull_number,
            }

            # Get diff if requested
            if include_diff:
                diff_response = self.mcp_client.get_pull_request_diff(owner, repo, pull_number)
                if diff_response.success:
                    diff_content = diff_response.result
                    # Truncate very long diffs
                    if isinstance(diff_content, str) and len(diff_content) > 100000:
                        diff_content = diff_content[:100000] + "\n... [truncated]"
                    result["diff"] = diff_content
                else:
                    result["diff_error"] = diff_response.error

            # Get comments if requested
            if include_comments:
                comments_response = self.mcp_client.get_pull_request_comments(owner, repo, pull_number)
                if comments_response.success:
                    result["comments"] = comments_response.result
                else:
                    result["comments_error"] = comments_response.error

            # Get reviews if requested (top-level approve/request changes actions)
            if include_reviews:
                reviews_response = self.mcp_client.get_pull_request_reviews(owner, repo, pull_number)
                if reviews_response.success:
                    result["reviews"] = reviews_response.result
                else:
                    result["reviews_error"] = reviews_response.error

            # Get review comments if requested (inline code comments - the actual feedback)
            if include_review_comments:
                review_comments_response = self.mcp_client.get_pull_request_review_comments(owner, repo, pull_number)
                if review_comments_response.success:
                    result["review_comments"] = review_comments_response.result
                else:
                    result["review_comments_error"] = review_comments_response.error

            suggestions = []
            pr_data = result.get("pr", {})
            if isinstance(pr_data, dict):
                files_changed = pr_data.get("changed_files", 0)
                if files_changed:
                    suggestions.append(
                        f"PR changes {files_changed} files. Use expand_node to understand affected code."
                    )

            return ToolResult.success_result(
                data=result,
                suggestions=suggestions,
            )

        except MCPError as e:
            return ToolResult.error_result(
                f"MCP error: {e}",
                suggestions=["Check MCP server status", "Verify GitHub token"],
            )
        except Exception as e:
            log.exception("GitHub PR details error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "pull_number": {
                    "type": "integer",
                    "description": "Pull request number",
                },
                "owner": {
                    "type": "string",
                    "description": "Repository owner (defaults to GITHUB_REPO config)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name (defaults to GITHUB_REPO config)",
                },
                "include_diff": {
                    "type": "boolean",
                    "default": True,
                    "description": "Include the PR diff",
                },
                "include_comments": {
                    "type": "boolean",
                    "default": True,
                    "description": "Include PR comments",
                },
                "include_reviews": {
                    "type": "boolean",
                    "default": True,
                    "description": "Include PR reviews (approve/request changes actions)",
                },
                "include_review_comments": {
                    "type": "boolean",
                    "default": True,
                    "description": "Include inline code review comments (the actual feedback)",
                },
            },
            required=["pull_number"],
        )


class GitHubListPRsTool(MCPBaseTool):
    """List pull requests in a repository with rich metadata."""

    name = "github_list_prs"
    description = (
        "List pull requests in a GitHub repository. "
        "Use this to see open, closed, or all PRs with metadata. "
        "More powerful than get_recent_prs as it queries GitHub directly. "
        "If owner/repo not specified, uses the configured GITHUB_REPO."
    )
    category = ToolCategory.HISTORY

    def execute(
        self,
        owner: Optional[str] = None,
        repo: Optional[str] = None,
        state: str = "open",
        per_page: int = 30,
    ) -> ToolResult:
        """List PRs in a repository.

        Args:
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)
            state: PR state filter (open, closed, all)
            per_page: Number of results (default 30, max 100)

        Returns:
            ToolResult with list of PRs
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        # ALWAYS use configured repo - never allow global operations
        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        if not owner or not repo:
            return ToolResult.error_result(
                "Repository owner and name are required. "
                "Set GITHUB_REPO in .env or provide owner/repo parameters.",
            )

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            response = self.mcp_client.list_pull_requests(
                owner=owner,
                repo=repo,
                state=state,
                per_page=min(per_page, 100),
            )

            if not response.success:
                return ToolResult.error_result(
                    f"Failed to list PRs: {response.error}",
                    suggestions=["Verify repository access"],
                )

            # GitHub API may return list directly or in items field
            result = response.result
            if isinstance(result, dict):
                raw_prs = result.get("items", result.get("pull_requests", []))
            elif isinstance(result, list):
                raw_prs = result
            else:
                raw_prs = []

            # Summarize PRs to essential fields only (avoid huge context from full API response)
            prs = []
            for pr in raw_prs:
                if isinstance(pr, dict):
                    prs.append({
                        "number": pr.get("number"),
                        "title": pr.get("title", "")[:200],  # Truncate long titles
                        "state": pr.get("state"),
                        "author": pr.get("user", {}).get("login") if isinstance(pr.get("user"), dict) else None,
                        "created_at": pr.get("created_at"),
                        "merged_at": pr.get("merged_at"),
                        "closed_at": pr.get("closed_at"),
                        "url": pr.get("html_url"),
                    })

            # Summarize counts
            open_count = sum(1 for pr in prs if pr.get("state") == "open")
            merged_count = sum(1 for pr in prs if pr.get("merged_at"))

            suggestions = []
            if open_count > 0:
                suggestions.append(f"{open_count} open PR(s) - use github_pr_details for more info")
            if merged_count > 0:
                suggestions.append(f"{merged_count} merged PR(s) in results")

            return ToolResult.success_result(
                data={
                    "prs": prs,
                    "count": len(prs),
                    "open_count": open_count,
                    "merged_count": merged_count,
                    "repository": f"{owner}/{repo}",
                },
                suggestions=suggestions,
            )

        except MCPError as e:
            return ToolResult.error_result(f"MCP error: {e}")
        except Exception as e:
            log.exception("GitHub list PRs error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "owner": {
                    "type": "string",
                    "description": "Repository owner (defaults to GITHUB_REPO config)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name (defaults to GITHUB_REPO config)",
                },
                "state": {
                    "type": "string",
                    "enum": ["open", "closed", "all"],
                    "default": "open",
                    "description": "PR state filter",
                },
                "per_page": {
                    "type": "integer",
                    "default": 30,
                    "description": "Number of results (max 100)",
                },
            },
            required=[],
        )


class GitHubSearchReposTool(MCPBaseTool):
    """Search for GitHub repositories."""

    name = "github_search_repos"
    description = (
        "Search for GitHub repositories by name, description, or topics. "
        "Use this to discover related projects, find libraries, or explore codebases."
    )

    def execute(
        self,
        query: str,
        per_page: int = 10,
    ) -> ToolResult:
        """Search for repositories.

        Args:
            query: Search query (e.g., "react state management")
            per_page: Number of results (default 10, max 100)

        Returns:
            ToolResult with matching repositories
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            response = self.mcp_client.search_repositories(
                query=query,
                per_page=min(per_page, 100),
            )

            if not response.success:
                return ToolResult.error_result(
                    f"Repository search failed: {response.error}",
                    suggestions=["Try different search terms"],
                )

            # GitHub API returns {total_count, incomplete_results, items}
            result = response.result
            if isinstance(result, dict):
                repos = result.get("items", [])
            elif isinstance(result, list):
                repos = result
            else:
                repos = []

            return ToolResult.success_result(
                data={"repositories": repos, "count": len(repos), "query": query},
                suggestions=[f"Found {len(repos)} repositories"],
            )

        except MCPError as e:
            return ToolResult.error_result(f"MCP error: {e}")
        except Exception as e:
            log.exception("GitHub search repos error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "query": {
                    "type": "string",
                    "description": "Search query",
                },
                "per_page": {
                    "type": "integer",
                    "default": 10,
                    "description": "Number of results (max 100)",
                },
            },
            required=["query"],
        )


class GitHubSearchPRsTool(MCPBaseTool):
    """Search for PRs by text using GitHub issue search."""

    name = "github_search_prs"
    description = (
        "Search for pull requests in the configured GitHub repository by text. "
        "Uses GitHub issue search with is:pr and in:title,body."
    )
    category = ToolCategory.HISTORY

    def execute(
        self,
        query: str,
        owner: Optional[str] = None,
        repo: Optional[str] = None,
        per_page: int = 20,
    ) -> ToolResult:
        """Search for PRs by text.

        Args:
            query: Search query (e.g., "image fixes")
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)
            per_page: Number of results (default 20, max 100)

        Returns:
            ToolResult with matching PRs
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        if not owner or not repo:
            return ToolResult.error_result(
                "Repository owner and name are required. "
                "Set GITHUB_REPO in .env or provide owner/repo parameters.",
            )

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            full_query = f"{query} repo:{owner}/{repo} is:pr in:title,body"
            response = self.mcp_client.search_issues(
                query=full_query,
                per_page=min(per_page, 100),
            )

            if not response.success:
                return ToolResult.error_result(
                    f"PR search failed: {response.error}",
                    suggestions=["Try different search terms"],
                )

            result = response.result
            if isinstance(result, dict):
                items = result.get("items", [])
            elif isinstance(result, list):
                items = result
            else:
                items = []

            prs = []
            for item in items:
                if not isinstance(item, dict):
                    continue
                if not item.get("pull_request"):
                    continue
                prs.append({
                    "number": item.get("number"),
                    "title": item.get("title", "")[:200],
                    "state": item.get("state"),
                    "author": item.get("user", {}).get("login") if isinstance(item.get("user"), dict) else None,
                    "created_at": item.get("created_at"),
                    "url": item.get("html_url"),
                })

            return ToolResult.success_result(
                data={"prs": prs, "count": len(prs), "query": full_query},
                suggestions=[f"Found {len(prs)} PR(s)"],
            )

        except MCPError as e:
            return ToolResult.error_result(f"MCP error: {e}")
        except Exception as e:
            log.exception("GitHub search PRs error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "query": {
                    "type": "string",
                    "description": "Search query",
                },
                "owner": {
                    "type": "string",
                    "description": "Repository owner (defaults to GITHUB_REPO config)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name (defaults to GITHUB_REPO config)",
                },
                "per_page": {
                    "type": "integer",
                    "default": 20,
                    "description": "Number of results (max 100)",
                },
            },
            required=["query"],
        )


class GitHubGetIssueTool(MCPBaseTool):
    """Get details of a GitHub issue."""

    name = "github_get_issue"
    description = (
        "Get details of a GitHub issue including description and comments. "
        "Use this to understand bug reports, feature requests, or discussions. "
        "If owner/repo not specified, uses the configured GITHUB_REPO."
    )
    category = ToolCategory.HISTORY

    def execute(
        self,
        issue_number: int,
        owner: Optional[str] = None,
        repo: Optional[str] = None,
    ) -> ToolResult:
        """Get issue details.

        Args:
            issue_number: Issue number
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)

        Returns:
            ToolResult with issue details
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        # ALWAYS use configured repo - never allow global operations
        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        if not owner or not repo:
            return ToolResult.error_result(
                "Repository owner and name are required. "
                "Set GITHUB_REPO in .env or provide owner/repo parameters.",
            )

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            response = self.mcp_client.get_issue(owner, repo, issue_number)

            if not response.success:
                return ToolResult.error_result(
                    f"Failed to get issue: {response.error}",
                    suggestions=["Check issue number", "Verify repository access"],
                )

            return ToolResult.success_result(
                data={
                    "issue": response.result,
                    "repository": f"{owner}/{repo}",
                    "number": issue_number,
                },
            )

        except MCPError as e:
            return ToolResult.error_result(f"MCP error: {e}")
        except Exception as e:
            log.exception("GitHub get issue error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "issue_number": {
                    "type": "integer",
                    "description": "Issue number",
                },
                "owner": {
                    "type": "string",
                    "description": "Repository owner (defaults to GITHUB_REPO config)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name (defaults to GITHUB_REPO config)",
                },
            },
            required=["issue_number"],
        )


class GitHubViewRepoStructureTool(MCPBaseTool):
    """View the structure of a GitHub repository."""

    name = "github_view_repo_structure"
    description = (
        "View the directory structure of a GitHub repository. "
        "Use this to understand project layout, find files, or explore codebases. "
        "If owner/repo not specified, uses the configured GITHUB_REPO."
    )

    def execute(
        self,
        path: str = "",
        owner: Optional[str] = None,
        repo: Optional[str] = None,
        branch: Optional[str] = None,
    ) -> ToolResult:
        """View repository structure.

        Args:
            path: Path within the repository (empty for root)
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)
            branch: Branch/ref name (optional)

        Returns:
            ToolResult with directory listing
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        # ALWAYS use configured repo - never allow global operations
        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        if not owner or not repo:
            return ToolResult.error_result(
                "Repository owner and name are required. "
                "Set GITHUB_REPO in .env or provide owner/repo parameters.",
            )

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            # Use get_file_contents which can list directories
            response = self.mcp_client.get_file_contents(
                owner=owner,
                repo=repo,
                path=path or ".",
                branch=branch,
            )

            if not response.success:
                return ToolResult.error_result(
                    f"Failed to view structure: {response.error}",
                    suggestions=["Check path", "Verify repository access"],
                )

            return ToolResult.success_result(
                data={
                    "structure": response.result,
                    "repository": f"{owner}/{repo}",
                    "path": path or "/",
                },
            )

        except MCPError as e:
            return ToolResult.error_result(f"MCP error: {e}")
        except Exception as e:
            log.exception("GitHub view repo structure error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "path": {
                    "type": "string",
                    "default": "",
                    "description": "Path within repository (empty for root)",
                },
                "owner": {
                    "type": "string",
                    "description": "Repository owner (defaults to GITHUB_REPO config)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name (defaults to GITHUB_REPO config)",
                },
                "branch": {
                    "type": "string",
                    "description": "Branch/ref name (optional)",
                },
            },
            required=[],
        )


class GitHubCreateReviewTool(MCPBaseTool):
    """Create a review on a pull request with optional inline comments."""

    name = "github_create_review"
    description = (
        "Create a review on a GitHub pull request. "
        "Can include a summary comment and inline code comments. "
        "Use event='APPROVE' to approve, 'REQUEST_CHANGES' to request changes, "
        "or 'COMMENT' for general feedback. "
        "WARNING: This actually posts to GitHub - use with care."
    )
    category = ToolCategory.HISTORY

    def execute(
        self,
        pull_number: int,
        body: str,
        event: str = "COMMENT",
        comments: Optional[list[dict]] = None,
        owner: Optional[str] = None,
        repo: Optional[str] = None,
    ) -> ToolResult:
        """Create a review on a pull request.

        Args:
            pull_number: PR number to review
            body: Review summary text
            event: Review action - 'APPROVE', 'REQUEST_CHANGES', or 'COMMENT'
            comments: Optional list of inline comments, each with:
                - path: File path relative to repo root
                - line: Line number in the diff
                - body: Comment text
                - side: 'LEFT' (old code) or 'RIGHT' (new code, default)
            owner: Repository owner (defaults to GITHUB_REPO config)
            repo: Repository name (defaults to GITHUB_REPO config)

        Returns:
            ToolResult with the created review details
        """
        error = self._ensure_mcp_available()
        if error:
            return error

        # Validate event
        valid_events = {"APPROVE", "REQUEST_CHANGES", "COMMENT"}
        if event.upper() not in valid_events:
            return ToolResult.error_result(
                f"Invalid event '{event}'. Must be one of: {', '.join(valid_events)}",
            )

        # ALWAYS use configured repo - never allow global operations
        owner, repo, repo_error = self._ensure_repo_context(owner, repo)
        if repo_error:
            return repo_error

        if not owner or not repo:
            return ToolResult.error_result(
                "Repository owner and name are required. "
                "Set GITHUB_REPO in .env or provide owner/repo parameters.",
            )

        try:
            if not self.mcp_client._initialized:
                self.mcp_client.start()

            # Note: The MCP client method will fail if in read_only mode
            response = self.mcp_client.create_pull_request_review(
                owner=owner,
                repo=repo,
                pull_number=pull_number,
                body=body,
                event=event.upper(),
                comments=comments,
            )

            if not response.success:
                return ToolResult.error_result(
                    f"Failed to create review: {response.error}",
                    suggestions=[
                        "Verify you have write access to the repository",
                        "Check that the PR number is valid",
                        "Ensure the MCP client is not in read-only mode",
                    ],
                )

            return ToolResult.success_result(
                data={
                    "review": response.result,
                    "pull_number": pull_number,
                    "repository": f"{owner}/{repo}",
                    "event": event.upper(),
                    "comments_count": len(comments) if comments else 0,
                },
            )

        except MCPError as e:
            return ToolResult.error_result(f"MCP error: {e}")
        except Exception as e:
            log.exception("GitHub create review error")
            return ToolResult.error_result(str(e))

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "pull_number": {
                    "type": "integer",
                    "description": "PR number to review",
                },
                "body": {
                    "type": "string",
                    "description": "Review summary text",
                },
                "event": {
                    "type": "string",
                    "enum": ["APPROVE", "REQUEST_CHANGES", "COMMENT"],
                    "default": "COMMENT",
                    "description": "Review action type",
                },
                "comments": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "path": {"type": "string", "description": "File path"},
                            "line": {"type": "integer", "description": "Line number"},
                            "body": {"type": "string", "description": "Comment text"},
                            "side": {
                                "type": "string",
                                "enum": ["LEFT", "RIGHT"],
                                "default": "RIGHT",
                                "description": "Side of the diff",
                            },
                        },
                        "required": ["path", "line", "body"],
                    },
                    "description": "Optional inline comments on specific lines",
                },
                "owner": {
                    "type": "string",
                    "description": "Repository owner (defaults to GITHUB_REPO config)",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name (defaults to GITHUB_REPO config)",
                },
            },
            required=["pull_number", "body"],
        )
