"""Already-landed controller handoff consistency verifier (#299)."""

from __future__ import annotations

import re
from typing import Any

from review_proofs import git_ref_mutating_commands

ALREADY_LANDED_STATE = "ALREADY_LANDED_RECONCILE_REQUIRED"

_HANDOFF_SECTION_RE = re.compile(r"^##\s*Controller Handoff\s*$", re.I | re.M)

_STALE_HANDOFF_FIELDS = (
    "pinned reviewed head",
    "scratch worktree used",
)

_LEGACY_MUTATIONS_NONE_RE = re.compile(
    r"^\s*[-*]?\s*mutations\s*:\s*none\s*$",
    re.I | re.M,
)
_LEGACY_WORKSPACE_NONE_RE = re.compile(
    r"^\s*[-*]?\s*workspace\s+mutations\s*:\s*none\s*$",
    re.I | re.M,
)

_FORBIDDEN_REVIEW_STATES_RE = re.compile(
    r"review decision\s*:\s*approved?\b|"
    r"merge result\s*:\s*merged\b|"
    r"\bready[_ ]to[_ ]merge\b",
    re.I,
)

_NARRATIVE_ELIGIBILITY_RE = re.compile(
    r"eligibility class\s*:\s*([^\n]+)",
    re.I,
)
_NARRATIVE_REVIEWED_SHA_RE = re.compile(
    r"reviewed head sha\s*:\s*([^\n]+)",
    re.I,
)
_NARRATIVE_WORKTREE_RE = re.compile(
    r"review worktree used\s*:\s*([^\n]+)",
    re.I,
)


def _handoff_field_map(report_text: str) -> dict[str, str]:
    text = report_text or ""
    match = _HANDOFF_SECTION_RE.search(text)
    if not match:
        return {}
    fields: dict[str, str] = {}
    for line in text[match.end() :].splitlines():
        stripped = line.strip().lstrip("-*").strip()
        if ":" not in stripped:
            continue
        key, value = stripped.split(":", 1)
        fields[key.strip().lower()] = value.strip()
    return fields


def _narrative_before_handoff(report_text: str) -> str:
    text = report_text or ""
    match = _HANDOFF_SECTION_RE.search(text)
    if not match:
        return text
    return text[: match.start()]


def _is_truthy(value: str) -> bool:
    lowered = (value or "").strip().lower()
    return lowered not in {"", "none", "n/a", "not applicable", "false", "no", "—", "-"}


def _gate_active(text: str, fields: dict[str, str], session: dict) -> bool:
    if session.get("gate_fired") or session.get("already_landed_gate_fired"):
        return True
    eligibility = (fields.get("eligibility class") or "").upper()
    if ALREADY_LANDED_STATE in eligibility:
        return True
    return ALREADY_LANDED_STATE.lower() in text.lower()


def assess_already_landed_handoff_report(
    report_text: str,
    *,
    handoff_session: dict | None = None,
    command_log: list | None = None,
) -> dict[str, Any]:
    """Reject stale handoff fields and narrative/handoff drift after the gate (#299)."""
    text = report_text or ""
    session = dict(handoff_session or {})
    fields = _handoff_field_map(text)
    reasons: list[str] = []

    if not _gate_active(text, fields, session):
        return {
            "proven": True,
            "block": False,
            "reasons": [],
            "gate_active": False,
            "safe_next_action": "proceed",
        }

    for stale_field in _STALE_HANDOFF_FIELDS:
        if stale_field in fields:
            reasons.append(
                f"already-landed handoff must not include stale field "
                f"'{stale_field.title()}' (#299)"
            )

    if _LEGACY_WORKSPACE_NONE_RE.search(text):
        reasons.append(
            "already-landed handoff must not include legacy "
            "'Workspace mutations: None' (#299)"
        )

    ref_commands = git_ref_mutating_commands(command_log or session.get("command_log"))
    mutations_observed = bool(
        ref_commands
        or session.get("mutations_observed")
        or session.get("mcp_mutations")
        or session.get("review_mutations")
    )
    if mutations_observed and _LEGACY_MUTATIONS_NONE_RE.search(text):
        reasons.append(
            "already-landed handoff must not claim 'Mutations: None' when "
            "git ref, MCP, review, merge, or cleanup mutations occurred (#299)"
        )

    git_ref_value = fields.get("git ref mutations", "").strip().lower()
    if ref_commands and (not git_ref_value or git_ref_value == "none"):
        reasons.append(
            "git fetch/ref updates must be reported under Git ref mutations (#299)"
        )

    reviewed_sha = fields.get("reviewed head sha", "")
    if reviewed_sha and _is_truthy(reviewed_sha):
        reasons.append(
            "already-landed handoff must use 'Reviewed head SHA: none' (#299)"
        )

    worktree_used = fields.get("review worktree used", "")
    if worktree_used and _is_truthy(worktree_used):
        reasons.append(
            "already-landed handoff must set Review worktree used: false (#299)"
        )

    candidate_sha = fields.get("candidate head sha", "")
    if not candidate_sha or candidate_sha.lower() in {"none", "n/a", "unknown"}:
        reasons.append(
            "already-landed handoff must include Candidate head SHA (#299)"
        )

    if _FORBIDDEN_REVIEW_STATES_RE.search(text):
        reasons.append(
            "already-landed handoff must not claim approved/merged/ready-to-merge (#299)"
        )

    narrative = _narrative_before_handoff(text)
    handoff_eligibility = (fields.get("eligibility class") or "").strip()
    narrative_eligibility = (
        _NARRATIVE_ELIGIBILITY_RE.search(narrative).group(1).strip()
        if _NARRATIVE_ELIGIBILITY_RE.search(narrative)
        else ""
    )
    if handoff_eligibility and narrative_eligibility:
        if handoff_eligibility.upper() != narrative_eligibility.upper():
            reasons.append(
                "narrative Eligibility class disagrees with controller handoff (#299)"
            )

    narrative_reviewed = (
        _NARRATIVE_REVIEWED_SHA_RE.search(narrative).group(1).strip()
        if _NARRATIVE_REVIEWED_SHA_RE.search(narrative)
        else ""
    )
    if narrative_reviewed and reviewed_sha:
        if narrative_reviewed.lower() != reviewed_sha.lower():
            reasons.append(
                "narrative Reviewed head SHA disagrees with controller handoff (#299)"
            )

    narrative_worktree = (
        _NARRATIVE_WORKTREE_RE.search(narrative).group(1).strip()
        if _NARRATIVE_WORKTREE_RE.search(narrative)
        else ""
    )
    if narrative_worktree and worktree_used:
        if narrative_worktree.lower() != worktree_used.lower():
            reasons.append(
                "narrative Review worktree used disagrees with controller handoff (#299)"
            )

    git_ref_narrative = "git ref mutations" in narrative.lower()
    if git_ref_narrative and git_ref_value:
        if "none" in git_ref_value and ref_commands:
            reasons.append(
                "narrative and handoff disagree on git ref mutation reporting (#299)"
            )

    proven = not reasons
    return {
        "proven": proven,
        "block": not proven,
        "reasons": list(dict.fromkeys(reasons)),
        "gate_active": True,
        "safe_next_action": (
            "emit canonical ALREADY_LANDED_RECONCILE_REQUIRED handoff without "
            "stale review/merge fields; align narrative and controller handoff"
            if reasons
            else "proceed"
        ),
    }