"""Pre-create issue duplicate gate (#207)."""

from __future__ import annotations

import re
import unicodedata

VERDICT_NO_DUPLICATE = "no_duplicate_found"
VERDICT_DUPLICATE = "duplicate_found"
VERDICT_AMBIGUOUS = "ambiguous_duplicate_stop"

_STOPWORDS = frozenset({"a", "an", "the", "and", "or", "for", "to", "of", "in", "on"})


def normalize_issue_title(title: str) -> str:
    """Lowercase, punctuation-stripped, whitespace-collapsed title."""
    text = unicodedata.normalize("NFKC", (title or "").strip().lower())
    text = re.sub(r"[^\w\s]", " ", text)
    text = re.sub(r"\s+", " ", text).strip()
    return text


def _title_tokens(title: str) -> set[str]:
    return {
        t for t in normalize_issue_title(title).split()
        if t and t not in _STOPWORDS
    }


def titles_near_duplicate(proposed: str, existing: str) -> bool:
    """True when normalized titles match or are near-duplicates."""
    norm_a = normalize_issue_title(proposed)
    norm_b = normalize_issue_title(existing)
    if not norm_a or not norm_b:
        return False
    if norm_a == norm_b:
        return True
    if norm_a in norm_b or norm_b in norm_a:
        return True
    tokens_a = _title_tokens(proposed)
    tokens_b = _title_tokens(existing)
    if not tokens_a or not tokens_b:
        return False
    overlap = tokens_a & tokens_b
    union = tokens_a | tokens_b
    ratio = len(overlap) / len(union)
    if ratio >= 0.85:
        return True
    wall_pair = (
        {"hard", "wall"} <= tokens_a and {"wall"} <= tokens_b
    ) or (
        {"hard", "wall"} <= tokens_b and {"wall"} <= tokens_a
    )
    return wall_pair


def assess_pre_create_duplicate(
    proposed_title: str,
    existing_issues: list[dict],
    *,
    duplicate_override_reason: str | None = None,
    split_from_issue: int | None = None,
) -> dict:
    """Evaluate duplicate risk immediately before issue creation."""
    proposed_title = (proposed_title or "").strip()
    if not proposed_title:
        return {
            "verdict": VERDICT_AMBIGUOUS,
            "performed": False,
            "reasons": ["issue title is required"],
            "matches": [],
        }

    override = (duplicate_override_reason or "").strip()
    if override and split_from_issue is not None:
        return {
            "verdict": VERDICT_NO_DUPLICATE,
            "performed": True,
            "override_applied": True,
            "split_from_issue": split_from_issue,
            "override_reason": override,
            "reasons": [],
            "matches": [],
        }

    matches = []
    for issue in existing_issues or []:
        existing_title = (issue.get("title") or "").strip()
        if not existing_title:
            continue
        if titles_near_duplicate(proposed_title, existing_title):
            matches.append({
                "number": issue.get("number"),
                "title": existing_title,
                "state": issue.get("state"),
            })

    if not matches:
        return {
            "verdict": VERDICT_NO_DUPLICATE,
            "performed": True,
            "normalized_title": normalize_issue_title(proposed_title),
            "reasons": [],
            "matches": [],
        }

    if len(matches) > 3:
        return {
            "verdict": VERDICT_AMBIGUOUS,
            "performed": False,
            "normalized_title": normalize_issue_title(proposed_title),
            "reasons": [
                "too many near-duplicate title matches; fail closed "
                "until operator clarifies"
            ],
            "matches": matches[:5],
        }

    return {
        "verdict": VERDICT_DUPLICATE,
        "performed": False,
        "normalized_title": normalize_issue_title(proposed_title),
        "reasons": [
            f"duplicate issue title blocked: matches existing "
            f"#{m['number']} ({m['state']})"
            for m in matches
        ],
        "matches": matches,
    }


def pre_create_issue_duplicate_gate(
    proposed_title: str,
    existing_issues: list[dict],
    *,
    duplicate_override_reason: str | None = None,
    split_from_issue: int | None = None,
    allow_override: bool = False,
) -> dict:
    """Alias for ``assess_pre_create_duplicate`` (#207 suggested name)."""
    reason = (duplicate_override_reason or "").strip()
    if allow_override and not reason:
        reason = "operator-approved split after duplicate review"
    return assess_pre_create_duplicate(
        proposed_title,
        existing_issues,
        duplicate_override_reason=reason or None,
        split_from_issue=split_from_issue,
    )


def assess_duplicate_search_proof(report_text: str, matches: list[dict]) -> dict:
    """Reject LLM duplicate summaries that omit known exact duplicates (#207)."""
    text = (report_text or "").lower()
    missing = []
    for match in matches or []:
        num = match.get("number")
        title = (match.get("title") or "").lower()
        if num is not None and f"#{num}" not in text and str(num) not in text:
            missing.append(f"issue #{num}")
        if title and title[:40] not in text:
            missing.append(f"title '{match.get('title')}'")
    if missing:
        return {
            "valid": False,
            "reasons": [
                "duplicate-search proof omitted required match: " + ", ".join(missing)
            ],
        }
    return {"valid": True, "reasons": []}