"""complyform-github-issues-sync — hourly GitHub Issues metadata sync.

Trigger: Hourly Cloud Scheduler.

Queries the GitHub Issues API for the ``complyform/complyform`` repository,
computes tier/severity distributions, average response time, and oldest
unresolved issue, then writes a singleton document to
``founder_metrics/github_issues``.

Contract: API failure is logged and the function returns 200.
"""

from __future__ import annotations

import logging
from datetime import UTC, datetime, timedelta
from typing import Any

import httpx

from backend.ops._shared import cloud_function_wrapper, log_action
from backend.shared.firestore import get_db

_log = logging.getLogger(__name__)

_GITHUB_API_BASE = "https://api.github.com"
_REPO = "complyform/complyform"


async def _get_github_token() -> str:
    """Retrieve GitHub token from Secret Manager."""
    from google.cloud import secretmanager

    client = secretmanager.SecretManagerServiceClient()
    name = "projects/complyform-prod/secrets/github-token/versions/latest"
    response = client.access_secret_version(request={"name": name})
    return response.payload.data.decode("utf-8")


def _extract_label_values(
    labels: list[dict[str, Any]],
    prefix: str,
) -> list[str]:
    """Extract label values with a given prefix (e.g. 'tier/' → 'pro')."""
    values: list[str] = []
    for label in labels:
        name = label.get("name", "")
        if name.startswith(prefix):
            values.append(name[len(prefix) :])
    return values


@cloud_function_wrapper("complyform-github-issues-sync")
async def github_issues_sync(request: Any) -> dict[str, Any]:
    """Sync GitHub Issues metadata to Firestore for founder dashboard."""
    token = await _get_github_token()
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/vnd.github+json",
        "X-GitHub-Api-Version": "2022-11-28",
    }

    issues: list[dict[str, Any]] = []
    page = 1
    async with httpx.AsyncClient(timeout=30.0) as client:
        while True:
            resp = await client.get(
                f"{_GITHUB_API_BASE}/repos/{_REPO}/issues",
                params={
                    "state": "all",
                    "per_page": 100,
                    "sort": "updated",
                    "page": page,
                },
                headers=headers,
            )
            resp.raise_for_status()
            batch = resp.json()
            if not batch:
                break
            issues.extend(batch)
            # Stop after retrieving all recently-updated issues (max ~1000)
            if len(batch) < 100 or page >= 10:
                break
            page += 1

    # Filter out pull requests (GitHub Issues API includes PRs)
    issues = [i for i in issues if "pull_request" not in i]

    now = datetime.now(UTC)
    cutoff_30d = now - timedelta(days=30)

    open_count = 0
    closed_30d = 0
    tier_dist: dict[str, int] = {"community": 0, "pro": 0, "team": 0, "agency": 0}
    severity_dist: dict[str, int] = {"p1": 0, "p2": 0, "p3": 0}
    response_times: list[float] = []
    oldest_unresolved: dict[str, Any] | None = None

    for issue in issues:
        state = issue.get("state", "")
        labels = issue.get("labels", [])
        created_at = issue.get("created_at", "")

        if state == "open":
            open_count += 1

            # Tier distribution
            tiers = _extract_label_values(labels, "tier/")
            for t in tiers:
                if t in tier_dist:
                    tier_dist[t] += 1
            if not tiers:
                tier_dist["community"] += 1

            # Severity distribution
            priorities = _extract_label_values(labels, "priority/")
            for p in priorities:
                if p in severity_dist:
                    severity_dist[p] += 1

            # Track oldest unresolved
            if created_at and (
                oldest_unresolved is None
                or created_at < oldest_unresolved.get("created_at", "")
            ):
                oldest_unresolved = {
                    "number": issue.get("number"),
                    "title": issue.get("title", ""),
                    "url": issue.get("html_url", ""),
                    "created_at": created_at,
                }

        elif state == "closed":
            closed_at = issue.get("closed_at", "")
            if closed_at:
                try:
                    closed_dt = datetime.fromisoformat(closed_at.replace("Z", "+00:00"))
                    if closed_dt >= cutoff_30d:
                        closed_30d += 1
                except ValueError, TypeError:
                    pass

        # Average response time (time to first comment)
        if state == "open" and issue.get("comments", 0) > 0 and created_at:
            try:
                created_dt = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
                # Approximate: use updated_at as proxy for first response
                # (precise would require fetching comments timeline)
                updated_at = issue.get("updated_at", "")
                if updated_at:
                    updated_dt = datetime.fromisoformat(
                        updated_at.replace("Z", "+00:00")
                    )
                    hours = (updated_dt - created_dt).total_seconds() / 3600
                    if hours >= 0:
                        response_times.append(hours)
            except ValueError, TypeError:
                pass

    avg_response_time = (
        round(sum(response_times) / len(response_times), 1) if response_times else None
    )

    result = {
        "open_count": open_count,
        "closed_count_30d": closed_30d,
        "tier_distribution": tier_dist,
        "severity_distribution": severity_dist,
        "avg_response_time_hours": avg_response_time,
        "oldest_unresolved": oldest_unresolved,
        "synced_at": now.isoformat(),
        "total_issues_scanned": len(issues),
    }

    # Write singleton document
    db = get_db()
    await db.collection("founder_metrics").document("github_issues").set(result)

    log_action(
        customer_id=None,
        action="github_issues_synced",
        record_count=len(issues),
        open_count=open_count,
    )
    return {"issues_scanned": len(issues), "open": open_count}


entry_point = github_issues_sync
