"""Pull Request Handler - manages Gitea pull requests, reviews, and merges"""

import json
from typing import Any

from plugins.gitea.client import GiteaClient


def get_tool_specifications() -> list[dict[str, Any]]:
    """Return tool specifications for ToolGenerator"""
    return [
        # === PULL REQUESTS ===
        {
            "name": "list_pull_requests",
            "method_name": "list_pull_requests",
            "description": "List pull requests in a Gitea repository with filters.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "state": {
                        "type": "string",
                        "description": "Filter by state",
                        "enum": ["open", "closed", "all"],
                        "default": "open",
                    },
                    "sort": {
                        "type": "string",
                        "description": "Sort by",
                        "enum": ["created", "updated", "comments", "recentupdate"],
                        "default": "created",
                    },
                    "labels": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Comma-separated label IDs",
                    },
                    "milestone": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Milestone name",
                    },
                    "page": {
                        "type": "integer",
                        "description": "Page number",
                        "default": 1,
                        "minimum": 1,
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Items per page (1-100)",
                        "default": 30,
                        "minimum": 1,
                        "maximum": 100,
                    },
                },
                "required": ["owner", "repo"],
            },
            "scope": "read",
        },
        {
            "name": "get_pull_request",
            "method_name": "get_pull_request",
            "description": "Get details of a specific pull request by number.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "read",
        },
        {
            "name": "create_pull_request",
            "method_name": "create_pull_request",
            "description": "Create a new pull request in a Gitea repository.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "title": {
                        "type": "string",
                        "description": "Pull request title",
                        "minLength": 1,
                        "maxLength": 255,
                    },
                    "head": {
                        "type": "string",
                        "description": "Source branch (head branch)",
                        "minLength": 1,
                    },
                    "base": {
                        "type": "string",
                        "description": "Target branch (base branch)",
                        "minLength": 1,
                    },
                    "body": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Pull request description (supports Markdown)",
                    },
                    "assignee": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Assignee username",
                    },
                    "assignees": {
                        "anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
                        "description": "List of assignee usernames",
                    },
                    "labels": {
                        "anyOf": [
                            {"type": "array", "items": {"type": "integer"}},
                            {"type": "null"},
                        ],
                        "description": "List of label IDs",
                    },
                    "milestone": {
                        "anyOf": [{"type": "integer"}, {"type": "null"}],
                        "description": "Milestone ID",
                    },
                },
                "required": ["owner", "repo", "title", "head", "base"],
            },
            "scope": "write",
        },
        {
            "name": "update_pull_request",
            "method_name": "update_pull_request",
            "description": "Update an existing pull request. Can modify title, body, state, assignees, labels, and milestone.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                    "title": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Pull request title",
                    },
                    "body": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Pull request description",
                    },
                    "state": {
                        "anyOf": [{"type": "string", "enum": ["open", "closed"]}, {"type": "null"}],
                        "description": "Pull request state",
                    },
                    "assignee": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Assignee username",
                    },
                    "assignees": {
                        "anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
                        "description": "List of assignee usernames",
                    },
                    "labels": {
                        "anyOf": [
                            {"type": "array", "items": {"type": "integer"}},
                            {"type": "null"},
                        ],
                        "description": "List of label IDs",
                    },
                    "milestone": {
                        "anyOf": [{"type": "integer"}, {"type": "null"}],
                        "description": "Milestone ID",
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "write",
        },
        {
            "name": "merge_pull_request",
            "method_name": "merge_pull_request",
            "description": "Merge a pull request using specified merge method.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                    "method": {
                        "type": "string",
                        "description": "Merge method",
                        "enum": ["merge", "rebase", "rebase-merge", "squash"],
                        "default": "merge",
                    },
                    "title": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Merge commit title",
                    },
                    "message": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Merge commit message",
                    },
                    "delete_branch_after_merge": {
                        "type": "boolean",
                        "description": "Delete source branch after merge",
                        "default": False,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "write",
        },
        {
            "name": "close_pull_request",
            "method_name": "close_pull_request",
            "description": "Close a pull request without merging.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "write",
        },
        {
            "name": "reopen_pull_request",
            "method_name": "reopen_pull_request",
            "description": "Reopen a closed pull request.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "write",
        },
        # === PR DETAILS ===
        {
            "name": "list_pr_commits",
            "method_name": "list_pr_commits",
            "description": "List all commits in a pull request.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "read",
        },
        {
            "name": "list_pr_files",
            "method_name": "list_pr_files",
            "description": "List all changed files in a pull request with additions/deletions count.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "read",
        },
        {
            "name": "get_pr_diff",
            "method_name": "get_pr_diff",
            "description": "Get the unified diff of a pull request.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "read",
        },
        {
            "name": "list_pr_comments",
            "method_name": "list_pr_comments",
            "description": "List all comments on a pull request.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "read",
        },
        {
            "name": "create_pr_comment",
            "method_name": "create_pr_comment",
            "description": "Add a comment to a pull request.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                    "body": {
                        "type": "string",
                        "description": "Comment body (supports Markdown)",
                        "minLength": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number", "body"],
            },
            "scope": "write",
        },
        # === PR REVIEWS ===
        {
            "name": "list_pr_reviews",
            "method_name": "list_pr_reviews",
            "description": "List all reviews on a pull request.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number"],
            },
            "scope": "read",
        },
        {
            "name": "create_pr_review",
            "method_name": "create_pr_review",
            "description": "Create a review for a pull request (approve, request changes, or comment).",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                    "event": {
                        "type": "string",
                        "description": "Review event type",
                        "enum": ["APPROVED", "REQUEST_CHANGES", "COMMENT"],
                    },
                    "body": {
                        "anyOf": [{"type": "string"}, {"type": "null"}],
                        "description": "Review comment (optional for APPROVED)",
                    },
                },
                "required": ["owner", "repo", "pr_number", "event"],
            },
            "scope": "write",
        },
        {
            "name": "request_pr_reviewers",
            "method_name": "request_pr_reviewers",
            "description": "Request reviewers for a pull request.",
            "schema": {
                "type": "object",
                "properties": {
                    "owner": {"type": "string", "description": "Repository owner", "minLength": 1},
                    "repo": {"type": "string", "description": "Repository name", "minLength": 1},
                    "pr_number": {
                        "type": "integer",
                        "description": "Pull request number",
                        "minimum": 1,
                    },
                    "reviewers": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "List of reviewer usernames",
                        "minItems": 1,
                    },
                },
                "required": ["owner", "repo", "pr_number", "reviewers"],
            },
            "scope": "write",
        },
    ]


async def list_pull_requests(
    client: GiteaClient,
    owner: str,
    repo: str,
    state: str = "open",
    sort: str = "created",
    labels: str | None = None,
    milestone: str | None = None,
    page: int = 1,
    limit: int = 30,
) -> str:
    """List repository pull requests"""
    params = {
        "state": state,
        "sort": sort,
        "labels": labels,
        "milestone": milestone,
        "page": page,
        "limit": limit,
    }
    prs = await client.list_pull_requests(owner, repo, params)
    result = {"success": True, "count": len(prs), "pull_requests": prs}
    return json.dumps(result, indent=2)


async def get_pull_request(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """Get pull request details"""
    pr = await client.get_pull_request(owner, repo, pr_number)
    result = {"success": True, "pull_request": pr}
    return json.dumps(result, indent=2)


async def create_pull_request(
    client: GiteaClient,
    owner: str,
    repo: str,
    title: str,
    head: str,
    base: str,
    body: str | None = None,
    assignee: str | None = None,
    assignees: list[str] | None = None,
    labels: list[int] | None = None,
    milestone: int | None = None,
) -> str:
    """Create a new pull request"""
    data = {
        "title": title,
        "head": head,
        "base": base,
        "body": body,
        "assignee": assignee,
        "assignees": assignees,
        "labels": labels,
        "milestone": milestone,
    }
    pr = await client.create_pull_request(owner, repo, data)
    result = {
        "success": True,
        "message": f"Pull request #{pr['number']} created successfully",
        "pull_request": pr,
    }
    return json.dumps(result, indent=2)


async def update_pull_request(
    client: GiteaClient, owner: str, repo: str, pr_number: int, **kwargs
) -> str:
    """Update a pull request"""
    # Build update data from kwargs
    data = {
        k: v for k, v in kwargs.items() if v is not None and k not in ["owner", "repo", "pr_number"]
    }

    pr = await client.update_pull_request(owner, repo, pr_number, data)
    result = {
        "success": True,
        "message": f"Pull request #{pr_number} updated successfully",
        "pull_request": pr,
    }
    return json.dumps(result, indent=2)


async def merge_pull_request(
    client: GiteaClient,
    owner: str,
    repo: str,
    pr_number: int,
    method: str = "merge",
    title: str | None = None,
    message: str | None = None,
    delete_branch_after_merge: bool = False,
) -> str:
    """Merge a pull request"""
    data: dict = {"Do": method}
    if title is not None:
        data["MergeTitleField"] = title
    if message is not None:
        data["MergeMessageField"] = message
    if delete_branch_after_merge:
        data["delete_branch_after_merge"] = True
    merge_result = await client.merge_pull_request(owner, repo, pr_number, data)
    result = {
        "success": True,
        "message": f"Pull request #{pr_number} merged successfully using {method}",
        "result": merge_result,
    }
    return json.dumps(result, indent=2)


async def close_pull_request(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """Close a pull request"""
    data = {"state": "closed"}
    pr = await client.update_pull_request(owner, repo, pr_number, data)
    result = {
        "success": True,
        "message": f"Pull request #{pr_number} closed successfully",
        "pull_request": pr,
    }
    return json.dumps(result, indent=2)


async def reopen_pull_request(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """Reopen a pull request"""
    data = {"state": "open"}
    pr = await client.update_pull_request(owner, repo, pr_number, data)
    result = {
        "success": True,
        "message": f"Pull request #{pr_number} reopened successfully",
        "pull_request": pr,
    }
    return json.dumps(result, indent=2)


# PR Details
async def list_pr_commits(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """List pull request commits"""
    commits = await client.list_pr_commits(owner, repo, pr_number)
    result = {"success": True, "count": len(commits), "commits": commits}
    return json.dumps(result, indent=2)


async def list_pr_files(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """List pull request files"""
    files = await client.list_pr_files(owner, repo, pr_number)
    result = {"success": True, "count": len(files), "files": files}
    return json.dumps(result, indent=2)


async def get_pr_diff(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """Get pull request diff"""
    diff = await client.get_pr_diff(owner, repo, pr_number)
    result = {"success": True, "diff": diff}
    return json.dumps(result, indent=2)


async def list_pr_comments(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """List pull request comments"""
    # PR comments are same as issue comments in Gitea API
    comments = await client.list_issue_comments(owner, repo, pr_number)
    result = {"success": True, "count": len(comments), "comments": comments}
    return json.dumps(result, indent=2)


async def create_pr_comment(
    client: GiteaClient, owner: str, repo: str, pr_number: int, body: str
) -> str:
    """Create pull request comment"""
    data = {"body": body}
    comment = await client.create_issue_comment(owner, repo, pr_number, data)
    result = {
        "success": True,
        "message": f"Comment added to pull request #{pr_number}",
        "comment": comment,
    }
    return json.dumps(result, indent=2)


# PR Reviews
async def list_pr_reviews(client: GiteaClient, owner: str, repo: str, pr_number: int) -> str:
    """List pull request reviews"""
    reviews = await client.list_pr_reviews(owner, repo, pr_number)
    result = {"success": True, "count": len(reviews), "reviews": reviews}
    return json.dumps(result, indent=2)


async def create_pr_review(
    client: GiteaClient, owner: str, repo: str, pr_number: int, event: str, body: str | None = None
) -> str:
    """Create pull request review"""
    data = {"event": event, "body": body}
    review = await client.create_pr_review(owner, repo, pr_number, data)
    result = {
        "success": True,
        "message": f"Review {event} added to pull request #{pr_number}",
        "review": review,
    }
    return json.dumps(result, indent=2)


async def request_pr_reviewers(
    client: GiteaClient, owner: str, repo: str, pr_number: int, reviewers: list[str]
) -> str:
    """Request pull request reviewers"""
    data = {"reviewers": reviewers}
    reviewers_result = await client.request_pr_reviewers(owner, repo, pr_number, data)
    result = {
        "success": True,
        "message": f"Reviewers requested for pull request #{pr_number}",
        "result": reviewers_result,
    }
    return json.dumps(result, indent=2)
