# Gitea API Client — Library Package
#
# Shared Gitea client providing connection-backed API helpers.
# Consumers call lib.require("gitea-client") and pass a conn dict
# obtained from connections.get("gitea").
#
# Entry points:
#   on_request(req) — REST API routes for browser-side consumers
#   Exported functions — Starlark consumers via lib.require()
#
# Modules available (via library permissions):
#   http       — outbound HTTP (api.http)
#   connections — credential resolution (connections.read)
#   db         — ext_gitea_client_* tables (db.read, db.write)
#   json       — encode/decode (universal)

load("star/http_helpers.star", "gitea_get", "gitea_post", "gitea_patch", "auth_headers", "resp")
load("star/repos.star", _repos_get = "get_repos")
load("star/issues.star", _issues_get = "get_issues", _issue_get = "get_issue", _issue_create = "create_issue", _issue_update = "update_issue", _comment_add = "add_comment")
load("star/ci.star", _ci_get = "get_ci_status")

# Re-export loaded functions so lib.require() can find them in globals.
# Starlark load() names are file-local; explicit assignment makes them global.
get_repos      = _repos_get
get_issues     = _issues_get
get_issue      = _issue_get
create_issue   = _issue_create
update_issue   = _issue_update
add_comment    = _comment_add
get_ci_status  = _ci_get


# ═══════════════════════════════════════════════
#  REST API routes (/s/gitea-client/api/*)
# ═══════════════════════════════════════════════

def on_request(req):
    path   = req["path"]
    method = req["method"]

    conn = _resolve_conn()
    if conn == None:
        return resp(400, {"error": "no gitea connection configured"})

    if method == "GET" and path == "/repos":
        repos = get_repos(conn)
        if repos == None:
            return resp(502, {"error": "gitea request failed"})
        return resp(200, {"data": repos})

    elif method == "GET" and path == "/issues":
        q = req.get("query", {})
        owner = _str(q.get("owner", ""))
        repo  = _str(q.get("repo", ""))
        state = _str(q.get("state", "")) or "open"
        if not owner or not repo:
            return resp(400, {"error": "owner and repo query params required"})
        issues = get_issues(conn, owner, repo, state)
        if issues == None:
            return resp(502, {"error": "gitea request failed"})
        return resp(200, {"data": issues, "count": len(issues)})

    elif method == "GET" and path.startswith("/issues/"):
        parts = path[len("/issues/"):].split("/", 2)
        if len(parts) < 3:
            return resp(400, {"error": "path must be /issues/:owner/:repo/:number"})
        owner, repo, num = parts[0], parts[1], int(parts[2])
        issue = get_issue(conn, owner, repo, num)
        if issue == None:
            return resp(404, {"error": "issue not found"})
        return resp(200, issue)

    elif method == "POST" and path == "/issues":
        body = json.decode(req.get("body", "{}"))
        result = create_issue(conn, body.get("owner", ""), body.get("repo", ""),
                              body.get("title", ""), body.get("body", ""),
                              body.get("labels", ""))
        if result == None:
            return resp(502, {"error": "failed to create issue"})
        return resp(201, result)

    elif method == "GET" and path == "/prs":
        q = req.get("query", {})
        owner = _str(q.get("owner", ""))
        repo  = _str(q.get("repo", ""))
        state = _str(q.get("state", "")) or "open"
        if not owner or not repo:
            return resp(400, {"error": "owner and repo query params required"})
        prs = get_prs(conn, owner, repo, state)
        if prs == None:
            return resp(502, {"error": "gitea request failed"})
        return resp(200, {"data": prs, "count": len(prs)})

    elif method == "GET" and path.startswith("/ci/"):
        parts = path[len("/ci/"):].split("/", 2)
        if len(parts) < 3:
            return resp(400, {"error": "path must be /ci/:owner/:repo/:ref"})
        owner, repo, ref = parts[0], parts[1], parts[2]
        result = get_ci_status(conn, owner, repo, ref)
        if result == None:
            return resp(502, {"error": "CI status request failed"})
        return resp(200, result)

    elif method == "POST" and path == "/sync":
        return _handle_sync(conn, req)

    return resp(404, {"error": "not found"})


# ═══════════════════════════════════════════════
#  PR helper (not large enough for its own file)
# ═══════════════════════════════════════════════

def get_prs(conn, owner, repo, state):
    """List pull requests for a repository."""
    state = state or "open"
    path = "/repos/" + owner + "/" + repo + "/pulls?state=" + state + "&limit=50"
    data = gitea_get(conn, path)
    if data == None:
        return None
    items = []
    for p in data:
        items.append({
            "number":     p.get("number", 0),
            "title":      p.get("title", ""),
            "state":      p.get("state", ""),
            "head":       p.get("head", {}).get("ref", ""),
            "base":       p.get("base", {}).get("ref", ""),
            "user":       (p.get("user") or {}).get("login", ""),
            "created_at": p.get("created_at", ""),
            "html_url":   p.get("html_url", ""),
            "mergeable":  p.get("mergeable", None),
        })
    return items


# ═══════════════════════════════════════════════
#  Sync handler — cache repos/issues to db tables
# ═══════════════════════════════════════════════

def _handle_sync(conn, req):
    """Sync repos and issues into local cache tables."""
    repos = get_repos(conn)
    if repos == None:
        return resp(502, {"error": "failed to fetch repos"})

    conn_id = conn.get("id", "default")

    # Clear and re-insert repos
    db.exec("DELETE FROM repos WHERE connection_id = ?", [conn_id])
    for r in repos:
        db.exec(
            "INSERT INTO repos (connection_id, full_name, owner, name, description, html_url, open_issues, synced_at) VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))",
            [conn_id, r["full_name"], r["owner"], r["name"], r.get("description", ""), r.get("html_url", ""), r.get("open_issues", 0)]
        )

    # Sync open issues for each repo
    issue_count = 0
    db.exec("DELETE FROM issues WHERE connection_id = ?", [conn_id])
    for r in repos:
        issues = get_issues(conn, r["owner"], r["name"], "open")
        if issues == None:
            continue
        for i in issues:
            labels_str = ",".join(i.get("labels", []))
            db.exec(
                "INSERT INTO issues (connection_id, repo_full_name, number, title, state, labels, assignee, body, created_at, synced_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))",
                [conn_id, r["full_name"], i["number"], i["title"], i["state"], labels_str, i.get("assignee", ""), "", i.get("created_at", "")]
            )
            issue_count += 1

    return resp(200, {"repos": len(repos), "issues": issue_count})


# ═══════════════════════════════════════════════
#  Helpers
# ═══════════════════════════════════════════════

def _resolve_conn():
    """Resolve the first available gitea connection."""
    return connections.get("gitea")

def _str(v):
    if v == None:
        return ""
    return str(v)
