"""Prior-blocker skip proof verifier for reviewer queue reports (#318)."""

from __future__ import annotations

import re
from typing import Any

_FULL_SHA = re.compile(r"\b[0-9a-f]{40}\b", re.IGNORECASE)
_SHORT_SHA = re.compile(r"\b[0-9a-f]{7,39}\b", re.IGNORECASE)
_PR_NUMBER_RE = re.compile(r"(?:\bPR\s*#?|#)(\d+)\b", re.IGNORECASE)
_BLOCKING_DECISION_RE = re.compile(
    r"(?:blocking review decision|review decision|blocking decision)\s*:\s*request[_ ]changes|"
    r"request[_ ]changes",
    re.IGNORECASE,
)
_BLOCKING_HEAD_RE = re.compile(
    r"(?:blocking review head(?:\s+sha)?|blocker head(?:\s+sha)?|review head at blocker)",
    re.IGNORECASE,
)
_HEAD_CHANGED_RE = re.compile(
    r"(?:head (?:changed|unchanged)|head sha (?:changed|unchanged)|"
    r"head changed (?:after|since) (?:the )?blocker|head unchanged since blocker)",
    re.IGNORECASE,
)
_BLOCKER_REASON_RE = re.compile(
    r"(?:reason (?:it )?remains blocked|remains blocked because|blocking category)",
    re.IGNORECASE,
)
_LIVE_BLOCKER_PROOF_RE = re.compile(
    r"(?:blocker revalidated live|live proof|gitea_get_pr_review_feedback|"
    r"gitea_view_pr|review feedback fetched|current review state)",
    re.IGNORECASE,
)
_BLOCKER_UNVERIFIED_RE = re.compile(r"\bBLOCKER_STATUS_UNVERIFIED\b")


def _pr_section(text: str, pr_number: int) -> str:
    lines = (text or "").splitlines()
    chunks: list[str] = []
    capture = False
    token = f"#{pr_number}"
    for line in lines:
        lower = line.lower()
        if token in lower or f"pr {pr_number}" in lower or f"pr#{pr_number}" in lower.replace(" ", ""):
            capture = True
            chunks.append(line)
            continue
        if capture:
            if _PR_NUMBER_RE.search(line) and token not in line.lower():
                break
            if line.strip() == "" and len(chunks) > 3:
                break
            chunks.append(line)
    if chunks:
        return "\n".join(chunks)
    return text or ""


def _has_head_sha(text: str, head_sha: str | None) -> bool:
    if not head_sha:
        return bool(_FULL_SHA.search(text) or _SHORT_SHA.search(text))
    head = head_sha.strip().lower()
    if head in text.lower():
        return True
    if len(head) >= 7 and head[:7] in text.lower():
        return True
    return bool(_FULL_SHA.search(text))


def assess_prior_blocker_skip_proof(
    report_text: str,
    *,
    skipped_prs: list[dict] | None = None,
) -> dict[str, Any]:
    """Validate live blocker proof for skipped earlier open PRs (#318)."""
    text = report_text or ""
    reasons: list[str] = []
    assessments: list[dict[str, Any]] = []

    for entry in skipped_prs or []:
        pr_number = entry.get("pr_number")
        if pr_number is None:
            reasons.append("skipped PR entry missing pr_number")
            continue
        pr_number = int(pr_number)
        section = _pr_section(text, pr_number)
        verified = entry.get("blocker_verified")
        head_changed = entry.get("head_changed_since_blocker")
        blocking_head = (entry.get("blocking_review_head_sha") or "").strip() or None
        current_head = (entry.get("head_sha") or "").strip() or None
        skip_reason = (entry.get("skip_reason") or entry.get("blocking_decision") or "").lower()

        item_reasons: list[str] = []

        if head_changed is True:
            item_reasons.append(
                f"PR #{pr_number} head changed after blocker; it cannot be skipped "
                "based on stale REQUEST_CHANGES"
            )

        if f"#{pr_number}" not in text.lower() and f"pr {pr_number}" not in text.lower():
            item_reasons.append(f"skipped PR #{pr_number} not documented in final report")

        if "request_changes" in skip_reason or entry.get("blocking_decision") == "request_changes":
            if verified is False:
                if not _BLOCKER_UNVERIFIED_RE.search(section):
                    item_reasons.append(
                        f"PR #{pr_number} blocker proof unavailable; report must classify "
                        "BLOCKER_STATUS_UNVERIFIED"
                    )
            else:
                if not _BLOCKING_DECISION_RE.search(section):
                    item_reasons.append(
                        f"PR #{pr_number} skip missing blocking review decision proof"
                    )
                if not _has_head_sha(section, current_head):
                    item_reasons.append(
                        f"PR #{pr_number} skip missing current head SHA"
                    )
                if blocking_head and not _BLOCKING_HEAD_RE.search(section):
                    if blocking_head.lower() not in section.lower():
                        item_reasons.append(
                            f"PR #{pr_number} skip missing blocking review head SHA"
                        )
                if head_changed is False and not _HEAD_CHANGED_RE.search(section):
                    item_reasons.append(
                        f"PR #{pr_number} skip missing head-changed-since-blocker proof"
                    )
                if not _BLOCKER_REASON_RE.search(section):
                    item_reasons.append(
                        f"PR #{pr_number} skip missing reason-it-remains-blocked"
                    )
                if not _LIVE_BLOCKER_PROOF_RE.search(section):
                    item_reasons.append(
                        f"PR #{pr_number} skip missing live blocker proof for this session"
                    )

        proven = not item_reasons
        assessments.append({
            "pr_number": pr_number,
            "proven": proven,
            "classification": (
                "BLOCKER_STATUS_UNVERIFIED"
                if verified is False
                else "BLOCKED_SKIPPED"
            ),
            "reasons": item_reasons,
        })
        reasons.extend(item_reasons)

    proven = not reasons
    return {
        "proven": proven,
        "block": not proven,
        "downgraded": False,
        "assessments": assessments,
        "reasons": reasons,
        "safe_next_action": (
            "fetch live review feedback and document blocker proof for each skipped PR, "
            "or classify BLOCKER_STATUS_UNVERIFIED"
            if reasons
            else "proceed"
        ),
    }