"""Reconciliation linked-issue live proof verifier (#300)."""

from __future__ import annotations

import re
from typing import Any

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

_LINKED_ISSUE_FIELD_RE = re.compile(
    r"linked issue\s*:\s*(.+)$",
    re.I | re.M,
)
_LINKED_ISSUE_STATUS_RE = re.compile(
    r"linked issue(?:\s+live)?\s+status\s*:\s*(.+)$",
    re.I | re.M,
)

_STATUS_CLAIM_RE = re.compile(
    r"\b(?:issue\s+#?\d+\s*\()?(open|closed|resolved)\b|"
    r"issue\s+(?:is\s+)?(open|closed|resolved)\b|"
    r"linked issue.*\b(open|closed|resolved)\b",
    re.I,
)
_NOT_VERIFIED_RE = re.compile(r"not verified in this session", re.I)

_LIVE_FETCH_PROOF_RE = re.compile(
    r"gitea_view_issue|issue fetched live|live issue fetch|"
    r"fetched linked issue.*(?:current|this) session|"
    r"linked issue (?:fetch|proof).*(?:current|this) session|"
    r"live linked issue proof",
    re.I,
)

_ISSUE_ACTION_RECOMMEND_RE = re.compile(
    r"(?:recommend(?:ed)?|should|must)\s+(?:close|reopen|comment on)\s+"
    r"(?:the\s+)?(?:linked\s+)?issue|"
    r"(?:close|reopen|comment on)\s+linked issue\s+#?\d+",
    re.I,
)
_CAPABILITY_PROOF_RE = re.compile(
    r"capability proof|exact capability|gitea_close_issue|"
    r"gitea_mark_issue|gitea_create_issue_comment|gitea_edit_issue",
    re.I,
)

_NO_LINKED_ISSUE_VALUES = frozenset({
    "",
    "none",
    "n/a",
    "not applicable",
    "no linked issue",
    "unknown",
})


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 _extract_linked_issue_number(text: str, fields: dict[str, str]) -> int | None:
    linked = fields.get("linked issue", "")
    if linked.lower() in _NO_LINKED_ISSUE_VALUES:
        return None
    match = re.search(r"#?(\d+)", linked)
    if match:
        return int(match.group(1))
    field_match = _LINKED_ISSUE_FIELD_RE.search(text)
    if field_match:
        num = re.search(r"#?(\d+)", field_match.group(1))
        if num:
            return int(num.group(1))
    return None


def _status_value(text: str, fields: dict[str, str]) -> str:
    for key in ("linked issue live status", "linked issue status"):
        if fields.get(key):
            return fields[key]
    match = _LINKED_ISSUE_STATUS_RE.search(text)
    return match.group(1).strip() if match else ""


def _live_proof_present(text: str, session: dict, issue_number: int | None) -> bool:
    if session.get("live_fetched") or session.get("verified_live"):
        return True
    if session.get("issue_fetch_proof"):
        return True
    if _LIVE_FETCH_PROOF_RE.search(text):
        return True
    if issue_number is not None:
        pattern = re.compile(
            rf"gitea_view_issue.*#?{issue_number}|"
            rf"issue\s+#?{issue_number}.*(?:fetched|viewed).*(?:current|this) session",
            re.I,
        )
        if pattern.search(text):
            return True
    return False


def assess_reconcile_linked_issue_report(
    report_text: str,
    *,
    reconcile_session: dict | None = None,
) -> dict[str, Any]:
    """Validate linked issue status claims in reconciliation handoffs (#300)."""
    text = report_text or ""
    session = dict(reconcile_session or {})
    fields = _handoff_field_map(text)
    reasons: list[str] = []

    issue_number = session.get("linked_issue_number")
    if issue_number is None:
        issue_number = _extract_linked_issue_number(text, fields)

    if issue_number is None:
        status = _status_value(text, fields)
        if status and status.lower() not in _NO_LINKED_ISSUE_VALUES:
            if _STATUS_CLAIM_RE.search(status):
                reasons.append(
                    "linked issue status reported without identifying the linked issue (#300)"
                )
        if not reasons:
            return {
                "proven": True,
                "block": False,
                "reasons": [],
                "linked_issue_number": None,
                "safe_next_action": "proceed",
            }

    status = _status_value(text, fields)
    status_lower = status.lower()

    if session.get("issue_missing"):
        if status_lower and "not verified" not in status_lower:
            reasons.append(
                "missing linked issue must be reported as "
                "'not verified in this session' (#300)"
            )
    elif status:
        if _NOT_VERIFIED_RE.search(status):
            pass
        elif _STATUS_CLAIM_RE.search(status):
            if not _live_proof_present(text, session, issue_number):
                reasons.append(
                    "linked issue open/closed/resolved status requires live "
                    "gitea_view_issue proof in the current session (#300)"
                )
        elif status_lower not in _NO_LINKED_ISSUE_VALUES:
            if not _live_proof_present(text, session, issue_number):
                reasons.append(
                    "linked issue status claim requires live fetch proof or "
                    "'not verified in this session' (#300)"
                )

    if _ISSUE_ACTION_RECOMMEND_RE.search(text):
        if not _CAPABILITY_PROOF_RE.search(text) and not session.get(
            "issue_action_capability_proven"
        ):
            reasons.append(
                "recommended linked issue close/reopen/comment requires "
                "exact capability proof (#300)"
            )

    proven = not reasons
    return {
        "proven": proven,
        "block": not proven,
        "reasons": list(dict.fromkeys(reasons)),
        "linked_issue_number": issue_number,
        "live_proof_present": _live_proof_present(text, session, issue_number),
        "safe_next_action": (
            "fetch linked issue with gitea_view_issue in this session or "
            "report 'Linked issue status: not verified in this session'"
            if reasons
            else "proceed"
        ),
    }