from typing import Annotated

import httpx
from arcade.sdk import ToolContext, tool
from arcade.sdk.auth import GitHub

from arcade_github.tools.utils import get_github_json_headers, get_url, handle_github_response


# Implements https://docs.github.com/en/rest/activity/starring?apiVersion=2022-11-28#star-a-repository-for-the-authenticated-user and https://docs.github.com/en/rest/activity/starring?apiVersion=2022-11-28#unstar-a-repository-for-the-authenticated-user  # noqa: E501
# Example `arcade chat` usage: "star the vscode repo owned by microsoft"
@tool(requires_auth=GitHub())
async def set_starred(
    context: ToolContext,
    owner: Annotated[str, "The owner of the repository"],
    name: Annotated[str, "The name of the repository"],
    starred: Annotated[bool, "Whether to star the repository or not"] = True,
) -> Annotated[
    str, "A message indicating whether the repository was successfully starred or unstarred"
]:
    """
    Star or un-star a GitHub repository.
    For example, to star microsoft/vscode, you would use:
    ```
    set_starred(owner="microsoft", name="vscode", starred=True)
    ```
    """
    url = get_url("user_starred", owner=owner, repo=name)
    headers = get_github_json_headers(
        context.authorization.token if context.authorization and context.authorization.token else ""
    )

    async with httpx.AsyncClient() as client:
        if starred:
            response = await client.put(url, headers=headers)
        else:
            response = await client.delete(url, headers=headers)

    handle_github_response(response, url)

    action = "starred" if starred else "unstarred"
    return f"Successfully {action} the repository {owner}/{name}"


# Implements https://docs.github.com/en/rest/activity/starring?apiVersion=2022-11-28#list-stargazers
# Example `arcade chat` usage: "list the stargazers for the ArcadeAI/arcade-ai repo"
@tool(requires_auth=GitHub())
async def list_stargazers(
    context: ToolContext,
    owner: Annotated[str, "The owner of the repository"],
    repo: Annotated[str, "The name of the repository"],
    limit: Annotated[
        int | None,
        "The maximum number of stargazers to return. "
        "If not provided, all stargazers will be returned.",
    ] = None,
) -> Annotated[dict, "A dictionary containing the stargazers for the specified repository"]:
    """List the stargazers for a GitHub repository."""
    url = get_url("repo_stargazers", owner=owner, repo=repo)
    headers = get_github_json_headers(
        context.authorization.token if context.authorization and context.authorization.token else ""
    )

    if limit is None:
        limit = 2**64 - 1

    per_page = min(limit, 100)
    page = 1
    stargazers: list[dict] = []

    async with httpx.AsyncClient() as client:
        while len(stargazers) < limit:
            response = await client.get(
                url, headers=headers, params={"per_page": per_page, "page": page}
            )
            handle_github_response(response, url)

            data = response.json()
            if not data:
                break

            stargazers.extend([
                {
                    "login": stargazer.get("login"),
                    "id": stargazer.get("id"),
                    "node_id": stargazer.get("node_id"),
                    "html_url": stargazer.get("html_url"),
                }
                for stargazer in data
            ])

            if len(data) < per_page:
                break

            page += 1

    stargazers = stargazers[:limit]
    return {"number_of_stargazers": len(stargazers), "stargazers": stargazers}
