"""GitHub integration via gh CLI."""

import asyncio
import json
import shutil


async def _gh(args: list[str], timeout: float = 30) -> tuple[str, str, int]:
    """Run a gh command and return (stdout, stderr, returncode)."""
    gh_path = shutil.which("gh")
    if not gh_path:
        raise ValueError(
            "GitHub CLI (gh) not found. Install with: brew install gh\n"
            "Then authenticate: gh auth login"
        )

    proc = await asyncio.create_subprocess_exec(
        gh_path, *args,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    try:
        stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout)
    except asyncio.TimeoutError:
        proc.kill()
        raise ValueError(f"gh command timed out after {timeout}s: gh {' '.join(args)}")

    return stdout.decode(), stderr.decode(), proc.returncode


def _repo_args(params: dict) -> list[str]:
    """Return ['-R', 'owner/repo'] if repo specified, else empty list."""
    repo = params.get("repo")
    return ["-R", repo] if repo else []


async def handler(params: dict) -> dict:
    """Handle GitHub operations via gh CLI."""
    action = params["action"]

    try:
        if action == "list_issues":
            return await _list_issues(params)
        elif action == "create_issue":
            return await _create_issue(params)
        elif action == "list_prs":
            return await _list_prs(params)
        elif action == "create_pr":
            return await _create_pr(params)
        elif action == "pr_review":
            return await _pr_review(params)
        elif action == "list_runs":
            return await _list_runs(params)
        elif action == "repo_info":
            return await _repo_info(params)
        else:
            return {"success": False, "message": f"Unknown action: {action}", "data": {}}
    except ValueError:
        raise
    except Exception as e:
        return {"success": False, "message": f"Error: {e}", "data": {}}


async def _list_issues(params: dict) -> dict:
    limit = min(int(params.get("limit") or 10), 50)
    state = params.get("state", "open")
    args = ["issue", "list", "--json", "number,title,state,author,labels,createdAt,url",
            "--limit", str(limit), "--state", state] + _repo_args(params)

    stdout, stderr, rc = await _gh(args)
    if rc != 0:
        return {"success": False, "message": f"gh error: {stderr.strip()}", "data": {}}

    issues = json.loads(stdout) if stdout.strip() else []
    return {
        "success": True,
        "message": f"Found {len(issues)} issue(s)",
        "data": {"issues": issues},
    }


async def _create_issue(params: dict) -> dict:
    title = params.get("title")
    if not title:
        raise ValueError("'title' is required for create_issue")

    args = ["issue", "create", "--title", title]
    if params.get("body"):
        args.extend(["--body", params["body"]])
    if params.get("labels"):
        args.extend(["--label", ",".join(params["labels"])])
    args += _repo_args(params)

    stdout, stderr, rc = await _gh(args)
    if rc != 0:
        return {"success": False, "message": f"gh error: {stderr.strip()}", "data": {}}

    return {
        "success": True,
        "message": f"Issue created: {stdout.strip()}",
        "data": {"url": stdout.strip()},
    }


async def _list_prs(params: dict) -> dict:
    limit = min(int(params.get("limit") or 10), 50)
    state = params.get("state", "open")
    args = ["pr", "list", "--json", "number,title,state,author,headRefName,baseRefName,createdAt,url",
            "--limit", str(limit), "--state", state] + _repo_args(params)

    stdout, stderr, rc = await _gh(args)
    if rc != 0:
        return {"success": False, "message": f"gh error: {stderr.strip()}", "data": {}}

    prs = json.loads(stdout) if stdout.strip() else []
    return {
        "success": True,
        "message": f"Found {len(prs)} PR(s)",
        "data": {"pull_requests": prs},
    }


async def _create_pr(params: dict) -> dict:
    title = params.get("title")
    if not title:
        raise ValueError("'title' is required for create_pr")

    args = ["pr", "create", "--title", title]
    if params.get("body"):
        args.extend(["--body", params["body"]])
    if params.get("base"):
        args.extend(["--base", params["base"]])
    if params.get("head"):
        args.extend(["--head", params["head"]])
    args += _repo_args(params)

    stdout, stderr, rc = await _gh(args)
    if rc != 0:
        return {"success": False, "message": f"gh error: {stderr.strip()}", "data": {}}

    return {
        "success": True,
        "message": f"PR created: {stdout.strip()}",
        "data": {"url": stdout.strip()},
    }


async def _pr_review(params: dict) -> dict:
    pr_number = params.get("pr_number")
    if not pr_number:
        raise ValueError("'pr_number' is required for pr_review")

    fields = (
        "number,title,state,body,author,headRefName,baseRefName,"
        "additions,deletions,files,reviews,comments,url"
    )
    args = [
        "pr", "view", str(pr_number), "--json", fields,
    ] + _repo_args(params)

    stdout, stderr, rc = await _gh(args)
    if rc != 0:
        return {"success": False, "message": f"gh error: {stderr.strip()}", "data": {}}

    pr_data = json.loads(stdout) if stdout.strip() else {}
    return {
        "success": True,
        "message": f"PR #{pr_number}: {pr_data.get('title', '')}",
        "data": pr_data,
    }


async def _list_runs(params: dict) -> dict:
    limit = min(int(params.get("limit") or 10), 30)
    args = ["run", "list", "--json", "databaseId,displayTitle,status,conclusion,headBranch,createdAt,url",
            "--limit", str(limit)] + _repo_args(params)

    stdout, stderr, rc = await _gh(args)
    if rc != 0:
        return {"success": False, "message": f"gh error: {stderr.strip()}", "data": {}}

    runs = json.loads(stdout) if stdout.strip() else []
    return {
        "success": True,
        "message": f"Found {len(runs)} workflow run(s)",
        "data": {"runs": runs},
    }


async def _repo_info(params: dict) -> dict:
    args = ["repo", "view", "--json",
            "name,owner,description,defaultBranchRef,stargazerCount,forkCount,isPrivate,url"
            ] + _repo_args(params)

    stdout, stderr, rc = await _gh(args)
    if rc != 0:
        return {"success": False, "message": f"gh error: {stderr.strip()}", "data": {}}

    repo_data = json.loads(stdout) if stdout.strip() else {}
    return {
        "success": True,
        "message": f"Repository: {repo_data.get('owner', {}).get('login', '')}/{repo_data.get('name', '')}",
        "data": repo_data,
    }
