#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""AP query and graded-inhibition helpers for gate_checks.py."""

import re
import sqlite3
from pathlib import Path

# N50: Graded inhibition thresholds (3-level gate system)
_HARD_BLOCK_THRESHOLD = 0.95   # HARD_BLOCK: certainty too high to ignore
_SOFT_BLOCK_THRESHOLD = 0.80   # SOFT_BLOCK: strong signal, prefer to avoid
# Below _SOFT_BLOCK_THRESHOLD -> ADVISORY

_CODE_SIGNAL_RE = re.compile(
    r"sys\.exit|subprocess|\.encoding|\bimport\s|\braise\s"
    r"|\bdef\s|\bclass\s|sys\.path|os\.environ|open\("
    r"|json\.|sqlite|brain_db|filelock|worker_tools"
    r"|hippocampus|pulse_brain|encoding="
    r"|NEVER\s+use\s|NEVER\s+call\s|NEVER\s+add\s"
    r"|NEVER\s+write\s|NEVER\s+wrap\s|NEVER\s+skip\s"
    r"|NEVER\s+remove\s|NEVER\s+hardcode\s",
    re.IGNORECASE,
)

def _build_fts_query(keywords: list) -> str:
    if not keywords:
        return ""
    return " OR ".join('"' + k + '"' for k in keywords)

def _is_code_prescriptive(rule: str) -> bool:
    return bool(_CODE_SIGNAL_RE.search(rule or ""))

def _query_anti_patterns(db_path: Path, keywords: list) -> list:
    if not keywords or not db_path.exists():
        return []
    fts_query = _build_fts_query(keywords)
    if not fts_query:
        return []
    try:
        conn = sqlite3.connect(str(db_path.resolve()), timeout=5)
        conn.row_factory = sqlite3.Row
        rows = conn.execute(
            "SELECT ap.id, ap.description, ap.rule, ap.evidence_count, "
            "ap.confidence, ap.domain, ap.status "
            "FROM anti_patterns ap "
            "JOIN knowledge_fts fts ON fts.item_id = ap.id "
            "WHERE fts.table_name = 'anti_patterns' "
            "  AND knowledge_fts MATCH ? "
            "  AND ap.status = 'active' "
            "ORDER BY ap.evidence_count DESC LIMIT 20",
            (fts_query,),
        ).fetchall()
        conn.close()
        return [
            dict(row) for row in rows
            if _is_code_prescriptive(
                dict(row).get("rule", "") or dict(row).get("description", "")
            )
        ]
    except Exception:
        return []

def _format_ap_block(ap: dict, file_path: str = "") -> str:
    confidence = float(ap.get("confidence") or 0.0)
    evidence_count = int(ap.get("evidence_count") or 0)
    rule = ap.get("rule") or ap.get("description") or "No rule text available."
    loc = f" in {file_path}" if file_path else ""
    return (
        f"BRAIN BLOCK: Anti-pattern detected{loc} (confidence {confidence:.2f})\n"
        f"Rule: {rule}\n"
        f"Evidence: {evidence_count} confirmed incidents\n"
        f"Action: Fix your code to avoid this pattern, then retry."
    )

def _is_relevant_to_content(ap_rule: str, content: str, file_path: str) -> bool:
    """False if the specific code pattern from the rule doesn't appear in content."""
    rule_lower = (ap_rule or "").lower()
    file_refs = re.findall(r'([\w_]+\.py)', rule_lower)
    if file_refs and file_path:
        fp_lower = file_path.lower().replace("\\", "/")
        if not any(ref in fp_lower for ref in file_refs):
            return False
    content_lower = (content or "").lower()
    _code_pats = re.findall(r'(?:sys\.exit|subprocess\.run|os\.system|eval\(|exec\()', rule_lower)
    if _code_pats and content_lower:
        if not any(pat in content_lower for pat in _code_pats):
            return False
    return True

def _graded_gate_result(confidence: float, message: str) -> dict:
    """N50: Return 3-level graded inhibition result instead of binary BLOCK/PASS.

    Levels:
      hard_block  — confidence >= 0.95: certainty too high to ignore
      soft_block  — 0.80 <= confidence < 0.95: strong signal, prefer to avoid
      advisory    — confidence < 0.80: informational, agent can override
    """
    if confidence >= _HARD_BLOCK_THRESHOLD:
        level = "hard_block"
    elif confidence >= _SOFT_BLOCK_THRESHOLD:
        level = "soft_block"
    else:
        level = "advisory"
    return {"level": level, "confidence": round(confidence, 4), "message": message}
