from __future__ import annotations

import logging

import httpx

from cve_mcp.cache.sqlite_cache import VulnCache
from cve_mcp.config import GITHUB_TOKEN, MAX_RESPONSE_BYTES

logger = logging.getLogger(__name__)

TTL_EXPLOIT = 3600  # 1 hour

GITHUB_SEARCH_URL = "https://api.github.com/search/repositories"


async def check_exploit_availability(
    cve_id: str,
    client: httpx.AsyncClient,
    cache: VulnCache,
) -> dict:
    """Search GitHub for public PoC exploit repositories for a CVE.

    Searches for repositories matching the CVE ID plus common exploit/PoC keywords,
    sorted by stars to surface the most credible results first.

    Returns a dict with cve_id, github_pocs list, has_public_exploit flag, and poc_count.
    """
    cache_key = f"exploit:{cve_id}"
    cached = await cache.get(cache_key)
    if cached:
        return cached

    result = {
        "cve_id": cve_id,
        "github_pocs": [],
        "has_public_exploit": False,
        "poc_count": 0,
    }

    headers = {"Accept": "application/vnd.github+json"}
    if GITHUB_TOKEN:
        headers["Authorization"] = f"token {GITHUB_TOKEN}"

    # Search for repositories matching the CVE ID
    try:
        resp = await client.get(
            GITHUB_SEARCH_URL,
            params={
                "q": f"{cve_id} poc exploit",
                "sort": "stars",
                "order": "desc",
                "per_page": 10,
            },
            headers=headers,
        )

        if resp.status_code == 403:
            logger.warning("GitHub API rate limited for exploit search of %s", cve_id)
            return result
        if resp.status_code == 422:
            logger.warning("GitHub search validation error for %s", cve_id)
            return result
        resp.raise_for_status()

        if len(resp.content) > MAX_RESPONSE_BYTES:
            raise ValueError("GitHub search response too large")

        data = resp.json()
        items = data.get("items", [])

        pocs = []
        for repo in items:
            full_name = repo.get("full_name", "")
            description = repo.get("description", "") or ""

            # Basic relevance filter: CVE ID should appear in name or description
            cve_lower = cve_id.lower()
            if cve_lower not in full_name.lower() and cve_lower not in description.lower():
                continue

            pocs.append(
                {
                    "repo": full_name,
                    "url": repo.get("html_url", ""),
                    "description": description[:500],
                    "stars": repo.get("stargazers_count", 0),
                    "forks": repo.get("forks_count", 0),
                    "language": repo.get("language", ""),
                    "created_at": repo.get("created_at", ""),
                    "updated_at": repo.get("updated_at", ""),
                    "open_issues": repo.get("open_issues_count", 0),
                }
            )

        result["github_pocs"] = pocs
        result["has_public_exploit"] = len(pocs) > 0
        result["poc_count"] = len(pocs)

    except httpx.HTTPStatusError as exc:
        logger.error(
            "GitHub exploit search failed (HTTP %d) for %s", exc.response.status_code, cve_id
        )
    except Exception as exc:
        logger.error("GitHub exploit search error for %s: %s", cve_id, exc)

    await cache.set(cache_key, result, TTL_EXPLOIT)
    return result
