"""
GitHub utilities: single repo cloning + org-wide repo listing.
"""

from __future__ import annotations

import logging
import re
import time
from pathlib import Path
from typing import List, Optional

import requests
from git import Repo
from git.exc import GitCommandError

logger = logging.getLogger(__name__)

_GH_API = "https://api.github.com"


# ── single repo helpers ──────────────────────────────────────────────────────

def is_github_url(target: str) -> bool:
    """Return True if target looks like a GitHub repo URL."""
    return bool(re.match(r"^https?://github\.com/[\w.-]+/[\w.-]+/?$", target))


def extract_repo_name(url: str) -> str:
    """Derive a safe local directory name from a GitHub URL."""
    m = re.search(r"github\.com/([\w.-]+)/([\w.-]+)", url)
    if m:
        return f"{m.group(1)}_{m.group(2)}"
    return "unknown_repo"


def clone_repository(url: str, dest_dir: Path, token: str = "") -> Optional[Path]:
    """
    Clone a GitHub repository into dest_dir/<repo_name>.

    Args:
        url:      HTTPS GitHub URL.
        dest_dir: Parent directory for the clone.
        token:    Optional GitHub personal access token.

    Returns:
        Path to the cloned repo, or None on failure.
    """
    repo_name = extract_repo_name(url)
    repo_path = dest_dir / repo_name

    if repo_path.exists():
        logger.info(f"Repository already exists at {repo_path}")
        return repo_path

    clone_url = _inject_token(url, token)

    try:
        logger.info(f"Cloning {url}")
        Repo.clone_from(clone_url, repo_path)
        logger.info(f"Cloned to {repo_path}")
        return repo_path
    except GitCommandError as exc:
        logger.error(f"Clone failed: {exc}")
        return None


# ── org scanner ──────────────────────────────────────────────────────────────

def list_org_repos(org: str, token: str = "") -> List[str]:
    """
    Return a list of clone URLs for all public repos in a GitHub org.

    Handles pagination and rate-limiting automatically.

    Args:
        org:   GitHub organisation name.
        token: Optional personal access token (increases rate limit).

    Returns:
        List of HTTPS clone URLs.
    """
    headers = {"Accept": "application/vnd.github+json"}
    if token:
        headers["Authorization"] = f"Bearer {token}"

    urls: List[str] = []
    page = 1

    while True:
        resp = requests.get(
            f"{_GH_API}/orgs/{org}/repos",
            headers=headers,
            params={"per_page": 100, "page": page, "type": "public"},
            timeout=15,
        )

        if resp.status_code == 403:
            # Rate limited – wait and retry once
            reset = int(resp.headers.get("X-RateLimit-Reset", time.time() + 60))
            wait = max(reset - int(time.time()), 5)
            logger.warning(f"GitHub rate limit hit. Waiting {wait}s …")
            time.sleep(wait)
            continue

        if resp.status_code == 404:
            logger.error(f"Organisation '{org}' not found on GitHub.")
            break

        resp.raise_for_status()
        repos = resp.json()
        if not repos:
            break

        for repo in repos:
            urls.append(repo["clone_url"])

        page += 1

    logger.info(f"Found {len(urls)} repos in org '{org}'")
    return urls


# ── helpers ───────────────────────────────────────────────────────────────────

def _inject_token(url: str, token: str) -> str:
    """Embed a PAT into an HTTPS GitHub URL for authenticated cloning."""
    if not token:
        return url
    return re.sub(r"^https://", f"https://{token}@", url)
