from __future__ import annotations

from typing import Any

from langgraph.config import get_config

from ..reviewer_findings import (
    FindingInteraction,
    ReviewerThreadMissingError,
    append_finding_interaction,
    get_finding,
    get_thread_id_from_runtime,
    thread_missing_tool_result,
    update_finding_fields,
)
from ..reviewer_publish import reply_to_review_comment
from ..utils.github_token import get_github_token


async def reply_to_finding_thread(finding_id: str, body: str) -> dict[str, Any]:
    """Reply to the GitHub review thread for a tracked finding."""
    if not body.strip():
        return {"success": False, "error": "Reply body is required"}

    config = get_config()
    configurable = config.get("configurable", {}) if isinstance(config, dict) else {}
    repo_config = configurable.get("repo") if isinstance(configurable, dict) else None
    pr_number = configurable.get("pr_number") if isinstance(configurable, dict) else None
    if (
        not isinstance(repo_config, dict)
        or not repo_config.get("owner")
        or not repo_config.get("name")
        or not isinstance(pr_number, int)
    ):
        return {"success": False, "error": "Missing repo or PR info in run config"}

    token = get_github_token()
    if not token:
        return {"success": False, "error": "No GitHub token available"}

    try:
        return await _reply_to_finding_thread_async(
            finding_id=finding_id,
            body=body,
            owner=str(repo_config["owner"]),
            repo=str(repo_config["name"]),
            pr_number=pr_number,
            token=token,
        )
    except ReviewerThreadMissingError as exc:
        return thread_missing_tool_result(exc)


async def _reply_to_finding_thread_async(
    *,
    finding_id: str,
    body: str,
    owner: str,
    repo: str,
    pr_number: int,
    token: str,
) -> dict[str, Any]:
    thread_id = get_thread_id_from_runtime()
    finding = await get_finding(thread_id, finding_id)
    if finding is None:
        return {"success": False, "error": f"No finding found with id {finding_id}"}

    comment_id = finding.get("github_review_comment_id")
    if not isinstance(comment_id, int):
        return {"success": False, "error": "Finding has no GitHub review comment mapping"}

    response = await reply_to_review_comment(
        owner=owner,
        repo=repo,
        pr_number=pr_number,
        review_comment_id=comment_id,
        body=body.strip(),
        token=token,
    )
    if response is None:
        return {"success": False, "error": "GitHub did not accept the reply"}

    reply_id = response.get("id")
    updates: dict[str, Any] = {"last_reconciliation_note": "Replied to GitHub review thread."}
    if isinstance(reply_id, int):
        updates["last_review_reply_comment_id"] = reply_id
    updated = await update_finding_fields(thread_id, finding_id, updates)
    interaction: FindingInteraction = {
        "kind": "bot_reply",
        "github_comment_id": reply_id if isinstance(reply_id, int) else None,
        "github_parent_comment_id": comment_id,
        "author": "open-swe[bot]",
        "body": body.strip(),
        "created_at": "",
        "needs_reassessment": False,
    }
    updated = await append_finding_interaction(thread_id, finding_id, interaction)
    return {"success": True, "finding": updated, "reply_id": reply_id}
