# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Gitea / Forgejo Skill

Manage repositories, issues, and pull requests on your Gitea or Forgejo instance.

Setup:
    GITEA_URL=https://gitea.example.org
    GITEA_TOKEN=your-api-token
"""

import logging
import os

import httpx

from familiar.core.utils import format_http_error

logger = logging.getLogger(__name__)

REQUEST_TIMEOUT = 30


# ---------------------------------------------------------------------------
# Configuration helpers
# ---------------------------------------------------------------------------


def _get_gitea_config() -> dict:
    return {
        "url": os.environ.get("GITEA_URL", "").rstrip("/"),
        "token": os.environ.get("GITEA_TOKEN", ""),
    }


def _gitea_configured() -> bool:
    cfg = _get_gitea_config()
    return bool(cfg["url"] and cfg["token"])


def _gitea_headers() -> dict:
    cfg = _get_gitea_config()
    return {"Authorization": f"token {cfg['token']}"}


# ---------------------------------------------------------------------------
# Tool handlers
# ---------------------------------------------------------------------------


def gitea_list_repos(data: dict) -> str:
    """List your repositories."""
    if not _gitea_configured():
        return (
            "Gitea not configured. Run /connect gitea to set up, or set GITEA_URL and GITEA_TOKEN."
        )

    cfg = _get_gitea_config()
    url = f"{cfg['url']}/api/v1/user/repos"

    try:
        resp = httpx.get(url, headers=_gitea_headers(), timeout=REQUEST_TIMEOUT)
        if resp.status_code != 200:
            return format_http_error("Gitea", status_code=resp.status_code, connect_cmd="gitea")

        repos = resp.json()
        if not repos:
            return "No repositories found."

        lines = [f"Your repositories ({len(repos)}):"]
        for repo in repos:
            name = repo.get("full_name", repo.get("name", "(unnamed)"))
            stars = repo.get("stars_count", 0)
            forks = repo.get("forks_count", 0)
            updated = repo.get("updated_at", "")[:10]
            lines.append(f"  {name}  stars:{stars} forks:{forks} updated:{updated}")
        return "\n".join(lines)

    except httpx.HTTPError as e:
        logger.error(f"Gitea list repos error: {e}")
        return format_http_error("Gitea", exception=e, connect_cmd="gitea")


def gitea_search_issues(data: dict) -> str:
    """Search issues in a repository."""
    if not _gitea_configured():
        return (
            "Gitea not configured. Run /connect gitea to set up, or set GITEA_URL and GITEA_TOKEN."
        )

    owner = data.get("owner", "").strip()
    repo = data.get("repo", "").strip()
    if not owner or not repo:
        return "Please provide owner and repo."

    state = data.get("state", "open")
    cfg = _get_gitea_config()
    url = f"{cfg['url']}/api/v1/repos/{owner}/{repo}/issues"
    params = {"state": state}

    try:
        resp = httpx.get(url, headers=_gitea_headers(), params=params, timeout=REQUEST_TIMEOUT)
        if resp.status_code != 200:
            return format_http_error("Gitea", status_code=resp.status_code, connect_cmd="gitea")

        issues = resp.json()
        if not issues:
            return f"No {state} issues in {owner}/{repo}."

        lines = [f"Issues in {owner}/{repo} ({state}):"]
        for issue in issues[:25]:
            number = issue.get("number", "?")
            title = issue.get("title", "(untitled)")
            labels = ", ".join(lbl.get("name", "") for lbl in issue.get("labels", []))
            label_str = f" [{labels}]" if labels else ""
            lines.append(f"  #{number}: {title}{label_str}")
        if len(issues) > 25:
            lines.append(f"  ... and {len(issues) - 25} more")
        return "\n".join(lines)

    except httpx.HTTPError as e:
        logger.error(f"Gitea search issues error: {e}")
        return format_http_error("Gitea", exception=e, connect_cmd="gitea")


def gitea_create_issue(data: dict) -> str:
    """Create a new issue in a repository."""
    if not _gitea_configured():
        return (
            "Gitea not configured. Run /connect gitea to set up, or set GITEA_URL and GITEA_TOKEN."
        )

    owner = data.get("owner", "").strip()
    repo = data.get("repo", "").strip()
    title = data.get("title", "").strip()
    body = data.get("body", "")

    if not owner or not repo:
        return "Please provide owner and repo."
    if not title:
        return "Please provide an issue title."

    cfg = _get_gitea_config()
    url = f"{cfg['url']}/api/v1/repos/{owner}/{repo}/issues"
    payload = {"title": title, "body": body}

    try:
        resp = httpx.post(url, headers=_gitea_headers(), json=payload, timeout=REQUEST_TIMEOUT)
        if resp.status_code in (200, 201):
            issue = resp.json()
            number = issue.get("number", "?")
            html_url = issue.get("html_url", "")
            return f"Created issue #{number}: {title}\n  {html_url}"
        return format_http_error("Gitea", status_code=resp.status_code, connect_cmd="gitea")

    except httpx.HTTPError as e:
        logger.error(f"Gitea create issue error: {e}")
        return format_http_error("Gitea", exception=e, connect_cmd="gitea")


def gitea_list_prs(data: dict) -> str:
    """List pull requests in a repository."""
    if not _gitea_configured():
        return (
            "Gitea not configured. Run /connect gitea to set up, or set GITEA_URL and GITEA_TOKEN."
        )

    owner = data.get("owner", "").strip()
    repo = data.get("repo", "").strip()
    if not owner or not repo:
        return "Please provide owner and repo."

    cfg = _get_gitea_config()
    url = f"{cfg['url']}/api/v1/repos/{owner}/{repo}/pulls"

    try:
        resp = httpx.get(url, headers=_gitea_headers(), timeout=REQUEST_TIMEOUT)
        if resp.status_code != 200:
            return format_http_error("Gitea", status_code=resp.status_code, connect_cmd="gitea")

        prs = resp.json()
        if not prs:
            return f"No open pull requests in {owner}/{repo}."

        lines = [f"Pull requests in {owner}/{repo}:"]
        for pr in prs[:25]:
            number = pr.get("number", "?")
            title = pr.get("title", "(untitled)")
            state = pr.get("state", "open")
            user = pr.get("user", {}).get("login", "")
            lines.append(f"  #{number} [{state}] {title}  by {user}")
        if len(prs) > 25:
            lines.append(f"  ... and {len(prs) - 25} more")
        return "\n".join(lines)

    except httpx.HTTPError as e:
        logger.error(f"Gitea list PRs error: {e}")
        return format_http_error("Gitea", exception=e, connect_cmd="gitea")


def gitea_repo_stats(data: dict) -> str:
    """Get repository statistics."""
    if not _gitea_configured():
        return (
            "Gitea not configured. Run /connect gitea to set up, or set GITEA_URL and GITEA_TOKEN."
        )

    owner = data.get("owner", "").strip()
    repo = data.get("repo", "").strip()
    if not owner or not repo:
        return "Please provide owner and repo."

    cfg = _get_gitea_config()
    url = f"{cfg['url']}/api/v1/repos/{owner}/{repo}"

    try:
        resp = httpx.get(url, headers=_gitea_headers(), timeout=REQUEST_TIMEOUT)
        if resp.status_code != 200:
            return format_http_error("Gitea", status_code=resp.status_code, connect_cmd="gitea")

        repo_data = resp.json()
        name = repo_data.get("full_name", repo_data.get("name", "(unnamed)"))
        stars = repo_data.get("stars_count", 0)
        forks = repo_data.get("forks_count", 0)
        open_issues = repo_data.get("open_issues_count", 0)
        size = repo_data.get("size", 0)
        default_branch = repo_data.get("default_branch", "main")
        description = repo_data.get("description", "")
        created = repo_data.get("created_at", "")[:10]
        updated = repo_data.get("updated_at", "")[:10]

        size_mb = size / 1024 if size else 0

        lines = [
            f"Repository: {name}",
            f"  Description: {description}" if description else "",
            f"  Stars: {stars}  Forks: {forks}  Open issues: {open_issues}",
            f"  Size: {size_mb:.1f} MB  Default branch: {default_branch}",
            f"  Created: {created}  Updated: {updated}",
        ]
        return "\n".join(line for line in lines if line)

    except httpx.HTTPError as e:
        logger.error(f"Gitea repo stats error: {e}")
        return format_http_error("Gitea", exception=e, connect_cmd="gitea")


# ---------------------------------------------------------------------------
# Tool definitions
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "name": "gitea_list_repos",
        "description": (
            "List all repositories owned by the authenticated user on Gitea or Forgejo. "
            "Shows full name, star count, fork count, and last update date for each repository. "
            "Requires GITEA_URL and GITEA_TOKEN to be configured."
        ),
        "input_schema": {"type": "object", "properties": {}},
        "handler": gitea_list_repos,
        "category": "gitea",
    },
    {
        "name": "gitea_search_issues",
        "description": (
            "Search issues in a Gitea or Forgejo repository filtered by state (open, closed, or all). "
            "Shows issue number, title, and labels for up to 25 results. "
            "Requires the repository owner and name."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "owner": {
                    "type": "string",
                    "description": "Repository owner",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name",
                },
                "state": {
                    "type": "string",
                    "description": "Issue state (open, closed, all)",
                    "default": "open",
                },
            },
            "required": ["owner", "repo"],
        },
        "handler": gitea_search_issues,
        "category": "gitea",
    },
    {
        "name": "gitea_create_issue",
        "description": (
            "Create a new issue in a Gitea or Forgejo repository with a title and optional Markdown body. "
            "This action requires user confirmation before execution. "
            "Returns the issue number and URL on success."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "owner": {
                    "type": "string",
                    "description": "Repository owner",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name",
                },
                "title": {
                    "type": "string",
                    "description": "Issue title",
                },
                "body": {
                    "type": "string",
                    "description": "Issue body (Markdown)",
                },
            },
            "required": ["owner", "repo", "title"],
        },
        "handler": gitea_create_issue,
        "confirm": True,
        "confirm_message": "Create a new issue on Gitea/Forgejo?",
        "risk_level": "medium",
        "category": "gitea",
    },
    {
        "name": "gitea_list_prs",
        "description": (
            "List open pull requests in a Gitea or Forgejo repository. "
            "Shows PR number, state, title, and author for up to 25 results. "
            "Requires the repository owner and name."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "owner": {
                    "type": "string",
                    "description": "Repository owner",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name",
                },
            },
            "required": ["owner", "repo"],
        },
        "handler": gitea_list_prs,
        "category": "gitea",
    },
    {
        "name": "gitea_repo_stats",
        "description": (
            "Get detailed repository statistics from Gitea or Forgejo including stars, forks, open issues, size, and default branch. "
            "Also shows the repository description, creation date, and last update date. "
            "Requires the repository owner and name."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "owner": {
                    "type": "string",
                    "description": "Repository owner",
                },
                "repo": {
                    "type": "string",
                    "description": "Repository name",
                },
            },
            "required": ["owner", "repo"],
        },
        "handler": gitea_repo_stats,
        "category": "gitea",
    },
]
