"""GitHub delivery layer — P5.1 + P5.2 + V2.2b

Posts PR security review comments and sets commit check statuses via the GitHub REST API.

Auth precedence (per call):
  1. GitHub App installation token (when installation_id is provided and App is configured)
  2. POSTURA_GITHUB_TOKEN (personal access token — legacy / fallback)

Public API:
    post_pr_comment(repo_full_name, pr_number, review, installation_id=None)   → URL or None
    set_commit_status(repo_full_name, commit_sha, review, installation_id=None) → URL or None
    create_check_run(repo_full_name, commit_sha, review, installation_id=None)  → URL or None
"""
from __future__ import annotations

import logging
from typing import Any

import requests

from postura.config import settings
from postura.models.findings import PRSecurityReview

logger = logging.getLogger(__name__)

_GITHUB_API = "https://api.github.com"
_POSTURA_CONTEXT = "postura/security"   # commit status context name
_CHECK_NAME = "POSTURA Security Review"


def _resolve_token(installation_id: int | None) -> str | None:
    """Return the best available auth token, or None if nothing is configured."""
    if installation_id is not None:
        try:
            from postura.delivery.github_app_auth import get_installation_token, is_app_configured
            if is_app_configured():
                return get_installation_token(installation_id)
        except Exception as exc:
            logger.warning("GitHub App token fetch failed, falling back to PAT: %s", exc)
    if settings.github_token:
        return settings.github_token
    return None


# ---------------------------------------------------------------------------
# P5.1 — PR comment
# ---------------------------------------------------------------------------

def post_pr_comment(
    repo_full_name: str,
    pr_number: int,
    review: PRSecurityReview,
    installation_id: int | None = None,
) -> str | None:
    """
    Post the security review as a GitHub PR comment.

    Args:
        repo_full_name: "owner/repo"
        pr_number: GitHub PR number
        review: completed PRSecurityReview
        installation_id: GitHub App installation ID (uses App auth when provided)

    Returns:
        URL of the created comment, or None on failure.
    """
    token = _resolve_token(installation_id)
    if not token:
        logger.warning("No GitHub auth configured (set POSTURA_GITHUB_TOKEN or GitHub App) — skipping PR comment")
        return None

    body = _format_pr_comment(review)
    url = f"{_GITHUB_API}/repos/{repo_full_name}/issues/{pr_number}/comments"

    resp = _gh_post(url, {"body": body}, token=token)
    if resp is None:
        return None

    comment_url = resp.get("html_url", "")
    logger.info("Posted PR comment: %s", comment_url)
    return comment_url


def _format_pr_comment(review: PRSecurityReview) -> str:
    """Format PRSecurityReview as a GitHub-flavored markdown comment."""
    risk_emoji = {
        "CRITICAL": "🔴",
        "HIGH": "🟠",
        "MEDIUM": "🟡",
        "LOW": "🟢",
        "NONE": "✅",
    }.get(review.risk_level, "⚪")

    block_line = ""
    if review.requires_block:
        block_line = "\n> ⛔ **This PR is blocked** pending security remediation.\n"

    issues_section = ""
    if review.top_issues:
        items = "\n".join(f"- {issue}" for issue in review.top_issues)
        issues_section = f"\n**Top issues:**\n{items}\n"

    analysis_section = ""
    if review.full_analysis:
        # Trim to avoid massive comments; keep first 2000 chars
        trimmed = review.full_analysis[:2000]
        if len(review.full_analysis) > 2000:
            trimmed += "\n\n_... (truncated — see full analysis in POSTURA dashboard)_"
        analysis_section = f"\n<details>\n<summary>Full analysis</summary>\n\n{trimmed}\n</details>\n"

    posture_line = ""
    if review.posture_delta != 0:
        direction = "degraded" if review.posture_delta > 0 else "improved"
        posture_line = f"\nPosture score {direction} by **{abs(review.posture_delta):.1f} points**.\n"

    return (
        f"## {risk_emoji} POSTURA Security Review\n\n"
        f"**Risk level:** `{review.risk_level}`  |  "
        f"**Commit:** `{review.commit_sha[:8]}`  |  "
        f"**Findings:** {review.finding_count}\n"
        f"{block_line}"
        f"{posture_line}"
        f"{issues_section}"
        f"{analysis_section}"
        f"\n---\n_Generated by [POSTURA](https://github.com/your-org/postura) "
        f"— Attack Surface Posture Agent_"
    )


# ---------------------------------------------------------------------------
# P5.2 — Commit status
# ---------------------------------------------------------------------------

def set_commit_status(
    repo_full_name: str,
    commit_sha: str,
    review: PRSecurityReview,
    installation_id: int | None = None,
) -> str | None:
    """
    Set a GitHub commit status for the reviewed commit.

    State is "failure" if review.requires_block, "success" otherwise.

    Returns the status URL or None on failure.
    """
    token = _resolve_token(installation_id)
    if not token:
        logger.warning("No GitHub auth configured — skipping commit status")
        return None

    state, description = _review_to_status(review)
    url = f"{_GITHUB_API}/repos/{repo_full_name}/statuses/{commit_sha}"

    payload = {
        "state": state,
        "description": description[:140],   # GitHub limit
        "context": _POSTURA_CONTEXT,
        "target_url": "",
    }
    resp = _gh_post(url, payload, token=token)
    if resp is None:
        return None

    status_url = resp.get("url", "")
    logger.info("Set commit status '%s' for %s: %s", state, commit_sha[:8], status_url)
    return status_url


def create_check_run(
    repo_full_name: str,
    commit_sha: str,
    review: PRSecurityReview,
    installation_id: int | None = None,
) -> str | None:
    """
    Create a GitHub Check Run for the commit.

    Requires GitHub App token or fine-grained PAT with 'checks: write' permission.
    Returns the check run URL or None on failure.
    """
    token = _resolve_token(installation_id)
    if not token:
        logger.warning("No GitHub auth configured — skipping check run")
        return None

    conclusion = "failure" if review.requires_block else (
        "action_required" if review.risk_level in ("CRITICAL", "HIGH") else "success"
    )

    summary = _format_check_summary(review)
    url = f"{_GITHUB_API}/repos/{repo_full_name}/check-runs"

    payload = {
        "name": _CHECK_NAME,
        "head_sha": commit_sha,
        "status": "completed",
        "conclusion": conclusion,
        "output": {
            "title": f"POSTURA: {review.risk_level} risk",
            "summary": summary,
        },
    }
    resp = _gh_post(url, payload, token=token)
    if resp is None:
        return None

    check_url = resp.get("html_url", "")
    logger.info("Created check run '%s' for %s: %s", conclusion, commit_sha[:8], check_url)
    return check_url


def _review_to_status(review: PRSecurityReview) -> tuple[str, str]:
    """Return (state, description) for GitHub commit status."""
    if review.requires_block:
        return "failure", f"POSTURA: {review.risk_level} risk — merge blocked"
    if review.risk_level in ("CRITICAL", "HIGH"):
        return "failure", f"POSTURA: {review.risk_level} risk — review required"
    if review.risk_level in ("MEDIUM",):
        return "pending", f"POSTURA: {review.risk_level} risk — {review.finding_count} findings"
    return "success", f"POSTURA: {review.risk_level} risk — {review.finding_count} findings"


def _format_check_summary(review: PRSecurityReview) -> str:
    lines = [f"**Risk level:** {review.risk_level}"]
    if review.top_issues:
        lines.append("**Top issues:**")
        lines.extend(f"- {i}" for i in review.top_issues[:5])
    if review.full_analysis:
        lines.append("")
        lines.append(review.full_analysis[:1000])
    return "\n".join(lines)


# ---------------------------------------------------------------------------
# HTTP helper
# ---------------------------------------------------------------------------

def _gh_post(url: str, payload: dict[str, Any], *, token: str) -> dict | None:
    """POST to GitHub API with auth. Returns response JSON or None on error."""
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/vnd.github+json",
        "X-GitHub-Api-Version": "2022-11-28",
    }
    try:
        resp = requests.post(url, json=payload, headers=headers, timeout=15)
        resp.raise_for_status()
        return resp.json()
    except requests.HTTPError as exc:
        logger.error("GitHub API error %s for %s: %s", exc.response.status_code, url, exc.response.text[:200])
        return None
    except Exception as exc:
        logger.error("GitHub API request failed for %s: %s", url, exc)
        return None
