# Copyright (C) 2026 GoodData Corporation

"""Resolve a PR review thread containing a given review comment."""

from __future__ import annotations

from typing import cast

from aida_mcp.tools.github.client import GithubApiError, github_get_json, github_post_graphql
from aida_mcp.tools.github.comments_types import ResolveResult
from aida_mcp.tools.github.comments_url import parse_review_comment_url


async def _find_thread_id_for_review_comment(*, repo: str, pr_number: int, comment_database_id: int) -> str:
    owner, name = repo.split("/", 1)

    query = """
    query($owner: String!, $name: String!, $pr: Int!, $after: String) {
      repository(owner: $owner, name: $name) {
        pullRequest(number: $pr) {
          reviewThreads(first: 50, after: $after) {
            pageInfo { hasNextPage endCursor }
            nodes {
              id
              isResolved
              comments(first: 50) {
                nodes { databaseId url }
              }
            }
          }
        }
      }
    }
    """

    after: str | None = None
    for _ in range(10):  # hard cap pages to avoid runaway output/calls
        data_obj = await github_post_graphql(
            query=query,
            variables={"owner": owner, "name": name, "pr": pr_number, "after": after},
        )
        if not isinstance(data_obj, dict):
            raise GithubApiError("Unexpected GraphQL response shape.")
        doc = cast(dict[str, object], data_obj)
        data_field = doc.get("data")
        if not isinstance(data_field, dict):
            raise GithubApiError("Unexpected GraphQL response shape (missing data).")
        data = cast(dict[str, object], data_field)
        repo_field_obj = data.get("repository")
        pr_field_obj: object | None = None
        if isinstance(repo_field_obj, dict):
            repo_field = cast(dict[str, object], repo_field_obj)
            pr_field_obj = repo_field.get("pullRequest")

        rt_field_obj: object | None = None
        if isinstance(pr_field_obj, dict):
            pr_field = cast(dict[str, object], pr_field_obj)
            rt_field_obj = pr_field.get("reviewThreads")

        threads_obj: object = []
        page_info_obj: object | None = None
        if isinstance(rt_field_obj, dict):
            rt_field = cast(dict[str, object], rt_field_obj)
            threads_obj = rt_field.get("nodes") or []
            page_info_obj = rt_field.get("pageInfo")

        if isinstance(threads_obj, list):
            threads = cast(list[object], threads_obj)
            for t_obj in threads:
                if not isinstance(t_obj, dict):
                    continue
                t = cast(dict[str, object], t_obj)
                comments_obj = t.get("comments")
                comments_nodes_obj: object = []
                if isinstance(comments_obj, dict):
                    comments = cast(dict[str, object], comments_obj)
                    comments_nodes_obj = comments.get("nodes") or []
                if not isinstance(comments_nodes_obj, list):
                    continue
                for c_obj in cast(list[object], comments_nodes_obj):
                    if not isinstance(c_obj, dict):
                        continue
                    c = cast(dict[str, object], c_obj)
                    if c.get("databaseId") == comment_database_id:
                        tid = t.get("id")
                        if isinstance(tid, str) and tid:
                            return tid

        page_info = cast(dict[str, object], page_info_obj) if isinstance(page_info_obj, dict) else None
        if page_info is None or page_info.get("hasNextPage") is not True:
            break
        after_raw = page_info.get("endCursor")
        after = after_raw if isinstance(after_raw, str) else None

    raise GithubApiError("Could not find review thread for the provided comment (not found within search limit).")


async def resolve_review_thread(*, comment_url: str) -> ResolveResult:
    repo, comment_id = parse_review_comment_url(comment_url)

    comment_obj = await github_get_json(f"/repos/{repo}/pulls/comments/{comment_id}")
    if not isinstance(comment_obj, dict):
        raise GithubApiError("Unexpected review comment response shape.")
    comment = cast(dict[str, object], comment_obj)
    pr_url = comment.get("pull_request_url")
    if not isinstance(pr_url, str) or not pr_url:
        raise GithubApiError("Comment is not associated with a pull request (unexpected).")
    pr_number_str = pr_url.rstrip("/").split("/")[-1]
    if not pr_number_str.isdigit():
        raise GithubApiError("Could not parse PR number from pull_request_url.")
    pr_number = int(pr_number_str)

    thread_id = await _find_thread_id_for_review_comment(repo=repo, pr_number=pr_number, comment_database_id=comment_id)

    mutation = """
    mutation($threadId: ID!) {
      resolveReviewThread(input: {threadId: $threadId}) {
        thread { id isResolved }
      }
    }
    """
    data_obj = await github_post_graphql(query=mutation, variables={"threadId": thread_id})
    resolved = False
    if isinstance(data_obj, dict):
        doc = cast(dict[str, object], data_obj)
        data_field = doc.get("data")
        if isinstance(data_field, dict):
            data = cast(dict[str, object], data_field)
            rrt = data.get("resolveReviewThread")
            if isinstance(rrt, dict):
                rrt_obj = cast(dict[str, object], rrt)
                thread = rrt_obj.get("thread")
                if isinstance(thread, dict):
                    thread_obj = cast(dict[str, object], thread)
                    resolved = thread_obj.get("isResolved") is True
    return {
        "ok": True,
        "repo": repo,
        "pr_number": pr_number,
        "thread_id": thread_id,
        "resolved": bool(resolved),
    }
