#!/usr/bin/env python3
"""
Shared Gitea API client for wizard fleet automation.

Usage as CLI:
    python -m devkit.gitea_client issues --repo Timmy_Foundation/hermes-agent --state open
    python -m devkit.gitea_client issue --repo Timmy_Foundation/hermes-agent --number 142
    python -m devkit.gitea_client create-comment --repo Timmy_Foundation/hermes-agent --number 142 --body "Update from Bezalel"
    python -m devkit.gitea_client prs --repo Timmy_Foundation/hermes-agent --state open

Usage as module:
    from devkit.gitea_client import GiteaClient
    client = GiteaClient()
    issues = client.list_issues("Timmy_Foundation/hermes-agent", state="open")
"""

import argparse
import json
import os
import sys
from typing import Any, Dict, List, Optional

import urllib.request


DEFAULT_BASE_URL = os.getenv("GITEA_URL", "https://forge.alexanderwhitestone.com")
DEFAULT_TOKEN = os.getenv("GITEA_TOKEN", "")


class GiteaClient:
    def __init__(self, base_url: str = DEFAULT_BASE_URL, token: str = DEFAULT_TOKEN):
        self.base_url = base_url.rstrip("/")
        self.token = token or ""

    def _request(
        self,
        method: str,
        path: str,
        data: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> Any:
        url = f"{self.base_url}/api/v1{path}"
        req_headers = {"Content-Type": "application/json", "Accept": "application/json"}
        if self.token:
            req_headers["Authorization"] = f"token {self.token}"
        if headers:
            req_headers.update(headers)

        body = json.dumps(data).encode() if data else None
        req = urllib.request.Request(url, data=body, headers=req_headers, method=method)

        try:
            with urllib.request.urlopen(req) as resp:
                return json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            return {"error": True, "status": e.code, "body": e.read().decode()}

    def list_issues(self, repo: str, state: str = "open", limit: int = 50) -> List[Dict]:
        return self._request("GET", f"/repos/{repo}/issues?state={state}&limit={limit}") or []

    def get_issue(self, repo: str, number: int) -> Dict:
        return self._request("GET", f"/repos/{repo}/issues/{number}") or {}

    def create_comment(self, repo: str, number: int, body: str) -> Dict:
        return self._request(
            "POST", f"/repos/{repo}/issues/{number}/comments", {"body": body}
        )

    def update_issue(self, repo: str, number: int, **fields) -> Dict:
        return self._request("PATCH", f"/repos/{repo}/issues/{number}", fields)

    def list_prs(self, repo: str, state: str = "open", limit: int = 50) -> List[Dict]:
        return self._request("GET", f"/repos/{repo}/pulls?state={state}&limit={limit}") or []

    def get_pr(self, repo: str, number: int) -> Dict:
        return self._request("GET", f"/repos/{repo}/pulls/{number}") or {}

    def create_pr(self, repo: str, title: str, head: str, base: str, body: str = "") -> Dict:
        return self._request(
            "POST",
            f"/repos/{repo}/pulls",
            {"title": title, "head": head, "base": base, "body": body},
        )


def _fmt_json(obj: Any) -> str:
    return json.dumps(obj, indent=2, ensure_ascii=False)


def main(argv: List[str] = None) -> int:
    argv = argv or sys.argv[1:]
    parser = argparse.ArgumentParser(description="Gitea CLI for wizard fleet")
    parser.add_argument("--repo", default="Timmy_Foundation/hermes-agent", help="Repository full name")
    parser.add_argument("--token", default=DEFAULT_TOKEN, help="Gitea API token")
    parser.add_argument("--base-url", default=DEFAULT_BASE_URL, help="Gitea base URL")
    sub = parser.add_subparsers(dest="cmd")

    p_issues = sub.add_parser("issues", help="List issues")
    p_issues.add_argument("--state", default="open")
    p_issues.add_argument("--limit", type=int, default=50)

    p_issue = sub.add_parser("issue", help="Get single issue")
    p_issue.add_argument("--number", type=int, required=True)

    p_prs = sub.add_parser("prs", help="List PRs")
    p_prs.add_argument("--state", default="open")
    p_prs.add_argument("--limit", type=int, default=50)

    p_pr = sub.add_parser("pr", help="Get single PR")
    p_pr.add_argument("--number", type=int, required=True)

    p_comment = sub.add_parser("create-comment", help="Post comment on issue/PR")
    p_comment.add_argument("--number", type=int, required=True)
    p_comment.add_argument("--body", required=True)

    p_update = sub.add_parser("update-issue", help="Update issue fields")
    p_update.add_argument("--number", type=int, required=True)
    p_update.add_argument("--title", default=None)
    p_update.add_argument("--body", default=None)
    p_update.add_argument("--state", default=None)

    p_create_pr = sub.add_parser("create-pr", help="Create a PR")
    p_create_pr.add_argument("--title", required=True)
    p_create_pr.add_argument("--head", required=True)
    p_create_pr.add_argument("--base", default="main")
    p_create_pr.add_argument("--body", default="")

    args = parser.parse_args(argv)
    client = GiteaClient(base_url=args.base_url, token=args.token)

    if args.cmd == "issues":
        print(_fmt_json(client.list_issues(args.repo, args.state, args.limit)))
    elif args.cmd == "issue":
        print(_fmt_json(client.get_issue(args.repo, args.number)))
    elif args.cmd == "prs":
        print(_fmt_json(client.list_prs(args.repo, args.state, args.limit)))
    elif args.cmd == "pr":
        print(_fmt_json(client.get_pr(args.repo, args.number)))
    elif args.cmd == "create-comment":
        print(_fmt_json(client.create_comment(args.repo, args.number, args.body)))
    elif args.cmd == "update-issue":
        fields = {k: v for k, v in {"title": args.title, "body": args.body, "state": args.state}.items() if v is not None}
        print(_fmt_json(client.update_issue(args.repo, args.number, **fields)))
    elif args.cmd == "create-pr":
        print(_fmt_json(client.create_pr(args.repo, args.title, args.head, args.base, args.body)))
    else:
        parser.print_help()
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())
