# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
Brain Analysis: Text similarity, counting, and neuroscience helpers.

Split from brain_utils.py for Law 7 compliance.
"""

from pathlib import Path


# === TEXT UTILITIES ===


def text_similarity(a: str, b: str) -> float:
    """Simple word-overlap Jaccard similarity (0.0-1.0)."""
    if not a or not b:
        return 0.0
    wa = set(a.lower().split())
    wb = set(b.lower().split())
    if not wa or not wb:
        return 0.0
    return len(wa & wb) / len(wa | wb)


def search_relevance(query: str, document: str) -> float:
    """Query-coverage similarity for search (0.0-1.0).

    Returns fraction of query words found in document.
    Unlike Jaccard, long documents don't dilute the score.
    """
    if not query or not document:
        return 0.0
    qw = set(query.lower().split())
    dw = set(document.lower().split())
    if not qw:
        return 0.0
    return len(qw & dw) / len(qw)


def extract_domain(filename: str) -> str:
    """Extract domain name from evidence filename."""
    name = filename.replace(".json", "")
    parts = name.split("_")
    return parts[0] if parts else "unknown"


# === COUNTING ===


def count_lines(path: Path) -> int:
    """Count lines in a file."""
    if not path.exists():
        return 0
    try:
        with open(path, "r", encoding="utf-8") as f:
            return sum(1 for _ in f)
    except OSError:
        return 0


def count_json_items(path: Path) -> int:
    """Count items in a JSON array file."""
    from .brain_io import load_json
    data = load_json(path)
    return len(data) if isinstance(data, list) else 0


def count_md_sections(path: Path) -> int:
    """Count ## sections in a markdown file."""
    if not path.exists():
        return 0
    try:
        with open(path, "r", encoding="utf-8") as f:
            return sum(1 for line in f if line.startswith("## "))
    except OSError:
        return 0


# === NEUROSCIENCE HELPERS ===


def compute_weighted_count(items: list, config: dict) -> float:
    """Weighted count: FAIL items weighted higher (error-driven learning #33-34)."""
    fail_weight = config.get("synthesis", {}).get("fail_weight", 2.5)
    total = 0.0
    for item in items:
        if item.get("type") == "fail":
            total += fail_weight
        else:
            total += 1.0
    return total


def compute_confidence_decay(confidence: float, days_old: int,
                             decay_rate: float = 0.005) -> float:
    """Apply confidence decay: loses decay_rate per day (#13)."""
    decayed = confidence * ((1.0 - decay_rate) ** days_old)
    return max(0.0, round(decayed, 4))


def detect_cross_domain_patterns(evidence_dir: Path) -> list:
    """Find patterns appearing in 2+ domains (transfer detection #16, #29)."""
    from .brain_io import load_json
    if not evidence_dir.exists():
        return []
    pattern_domains = {}
    for ef in sorted(evidence_dir.glob("*.json")):
        domain = extract_domain(ef.name)
        items = load_json(ef)
        if isinstance(items, list):
            for item in items:
                p = item.get("pattern", "")
                if p:
                    pattern_domains.setdefault(p, set()).add(domain)
    return [{"pattern": p, "domains": sorted(d), "count": len(d),
             "universal": len(d) >= 3}
                         for p, d in pattern_domains.items() if len(d) >= 2]


def get_brain_density() -> dict:
    """Calculates synaptic density and integrity across all evidence chambers."""
    from .brain_io import load_json
    from .brain_utils import EVIDENCE_DIR, PRIVATE_DIR
    stats = {"total_items": 0, "signed_items": 0, "domains": 0}
    chambers = [EVIDENCE_DIR, PRIVATE_DIR]

    for chamber in chambers:
        if not chamber.exists(): continue
        for ef in chamber.rglob("*.json"):
            items = load_json(ef)
            if not isinstance(items, list): continue
            stats["domains"] += 1
            for item in items:
                stats["total_items"] += 1
                if "_signature" in item:
                    stats["signed_items"] += 1

    stats["integrity_ratio"] = stats["signed_items"] / stats["total_items"] if stats["total_items"] > 0 else 1.0
    return stats
