#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
Brain Search Sources (Core): Anti-patterns, wins, fails, evidence (V43.13)

Core search functions for primary brain regions.
All functions have the same signature: (query: str, config: dict) -> list

Dependencies: Python stdlib + brain_utils + search_utils
"""

import sys
from pathlib import Path

SCRIPT_DIR = Path(__file__).resolve().parent
ROOT_DIR = SCRIPT_DIR.parent.parent

from pulse.core.brain_utils import (load_json, load_json_dict, search_relevance,
                         EVIDENCE_DIR, ROOT_DIR, STATE_DIR)
from .search_utils import compute_salience, days_since, get_retrieval_count


def search_predictions(query: str, config: dict) -> list:
    """Search active prediction alerts (Phase 8 feedback loop)."""
    results = []
    alerts_file = STATE_DIR / "prediction_alerts.json"
    if not alerts_file.exists():
        return results

    data = load_json_dict(alerts_file)
    for alert in data.get("alerts", []):
        if alert.get("status") != "active":
            continue
        
        # Match against task title + prediction text
        search_text = f"{alert.get('task_title', '')} {alert.get('prediction', '')}"
        sim = search_relevance(query, search_text)
        
        # High threshold (0.4) because predictions are specific to tasks
        # If matched, give HUGE salience boost (it's an active warning)
        if sim >= 0.4:
            days = days_since(alert.get("timestamp", ""))
            results.append({
                "source": "predictions",
                "title": f"[PREDICTION] {alert.get('task_title', '')[:40]}...",
                "text": alert.get("prediction", "")[:300],
                "relevance": round(sim, 3),
                "salience": compute_salience(sim, days, config, 10.0), # 10x boost
                "severity": "critical",
                "confidence": alert.get("confidence", 0.5),
                "task_id": alert.get("task_id", "")
            })
            
    return sorted(results, key=lambda x: -x["salience"])


def search_anti_patterns(query: str, config: dict) -> list:
    """Search ANTI_PATTERNS.md and active anti-pattern registry for warnings."""
    results = []

    # 1. Search static ANTI_PATTERNS.md
    ap_file = ROOT_DIR / "Hippocampus" / "Patterns" / "anti_patterns.md"
    if ap_file.exists():
        with open(ap_file, "r", encoding="utf-8") as f:
            content = f.read()
        sections = content.split("## ")
        for section in sections[1:]:
            lines = section.strip().split("\n")
            title = lines[0].strip()
            body = "\n".join(lines[1:]).strip()
            sim = search_relevance(query, f"{title} {body}")
            if sim >= 0.2:
                results.append({
                    "source": "anti_patterns", "title": title,
                    "text": body[:200], "relevance": round(sim, 3),
                    "salience": compute_salience(sim, 0, config,
                                                 retrieval_count=get_retrieval_count(body[:200])),
                    "severity": "warning"
                })

    # 2. Search active anti-patterns registry (auto-built from DON'T_WANTS)
    active_ap_file = EVIDENCE_DIR / "Anti_Patterns" / "anti_patterns_active.json"
    if active_ap_file.exists():
        active = load_json(active_ap_file)
        for ap in active:
            if ap.get("status") != "active":
                continue
            desc = ap.get("description", "")
            rule = ap.get("rule", "")
            keywords = " ".join(ap.get("keywords", []))
            search_text = f"{desc} {rule} {keywords}"
            sim = search_relevance(query, search_text)
            if sim >= 0.2:
                days = days_since(ap.get("created", ""))
                results.append({
                    "source": "anti_patterns",
                    "title": f"[ACTIVE] {desc[:60]}",
                    "text": rule[:200] if rule else desc[:200],
                    "relevance": round(sim, 3),
                    "salience": compute_salience(sim, days, config,
                                                 retrieval_count=get_retrieval_count(desc[:200])),
                    "severity": ap.get("severity", "medium"),
                    "evidence_count": ap.get("evidence_count", 0),
                })

    # 3. Search reflex arc patterns (instant detections from bridge)
    reflex_file = EVIDENCE_DIR / "Anti_Patterns" / "reflex_patterns.json"
    if reflex_file.exists():
        reflex_data = load_json_dict(reflex_file)
        for rx in (reflex_data.get("entries", [])
                   if isinstance(reflex_data, dict) else []):
            if rx.get("status") != "active":
                continue
            desc = rx.get("description", "")
            sim = search_relevance(query, f"{desc} {rx.get('pattern_name', '')}")
            if sim >= 0.2:
                days = days_since(rx.get("timestamp", ""))
                results.append({
                    "source": "reflex_arc",
                    "title": f"[REFLEX] {desc[:60]}",
                    "text": desc[:200],
                    "relevance": round(sim, 3),
                    "salience": compute_salience(sim, days, config,
                                                 retrieval_count=get_retrieval_count(desc[:200])),
                    "severity": rx.get("severity", "medium"),
                })

    return sorted(results, key=lambda x: -x["salience"])


def search_evidence(query: str, config: dict) -> list:
    """Search raw evidence files (wants, dont_wants, sessions, learnings, etc.)."""
    results = []
    if not EVIDENCE_DIR.exists():
        return results
    for ef in sorted(EVIDENCE_DIR.rglob("*.json")):
        items = load_json(ef)
        if not isinstance(items, list):
            continue
        for item in items:
            # Extended fallback chain — covers all known key formats
            text = (item.get("evidence", "")
                    or item.get("want", "")
                    or item.get("dont_want", "")
                    or item.get("description", "")
                    or item.get("text", "")
                    or item.get("lesson", "")
                    or item.get("discovery", "")
                    or item.get("decision", "")
                    or item.get("issue", "")
                    or item.get("user_insight", ""))
            # Domain learnings: combine prompt + response summaries
            if not text and item.get("prompt_summary"):
                ps = item.get("prompt_summary", "")
                rs = item.get("response_summary", "")
                text = f"{ps} {rs}".strip() if rs else ps
            # Agent sessions: combine learnings + failures lists
            if not text:
                parts = []
                if isinstance(item.get("learnings"), list):
                    parts.extend(item["learnings"])
                elif isinstance(item.get("learnings"), str) and item["learnings"]:
                    parts.append(item["learnings"])
                if isinstance(item.get("failures"), list):
                    parts.extend(item["failures"])
                elif isinstance(item.get("failures"), str) and item["failures"]:
                    parts.append(item["failures"])
                if parts:
                    text = " ".join(parts)
            # Always prepend domain for topic matching
            domain = item.get("domain", "")
            if domain and text:
                text = f"{domain} {text}"
            sim = search_relevance(query, text)
            if sim >= 0.2:
                days = days_since(item.get("date") or item.get("timestamp"))
                item_sal = item.get("salience", 1.0)
                results.append({
                    "source": "evidence", "file": ef.name,
                    "text": text[:200], "relevance": round(sim, 3),
                    "salience": compute_salience(sim, days, config, item_sal,
                                                 retrieval_count=get_retrieval_count(text[:200])),
                    "confidence": item.get("confidence", 0.5),
                    "type": item.get("type", "observation")
                })
    return sorted(results, key=lambda x: -x["salience"])
