# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
Capture Routing: Evidence bucket routing, similarity scoring, synthesis triggers.

Split from auto_capture.py for Law 7 compliance.
Contains helpers for routing captured data to evidence buckets,
counting similar wants/dont_wants, domain routing, growth metrics,
and batch capture modes (from JSON and log files).

Dependencies: brain_utils, wants_parser (Python stdlib only via Law 4)
"""

import json
import logging
import re
import sys
from datetime import datetime, timezone
from pathlib import Path

# Add Brain + Shared to path for sibling imports

from pulse.core.brain_utils import (
    EVIDENCE_DIR,
    GROWTH_METRICS,
    load_config,
    load_json,
    load_json_dict,
    save_json,
)
from pulse.core.pii_filter import redact_pii

log = logging.getLogger("auto_capture")

# Evidence bucket files (semantic subfolders)
WANTS_EVIDENCE = EVIDENCE_DIR / "Intents" / "wants.json"
DONT_WANTS_EVIDENCE = EVIDENCE_DIR / "Intents" / "dont_wants.json"
SESSION_EVIDENCE = EVIDENCE_DIR / "Sessions" / "current_session.json"
ANTI_PATTERNS_ACTIVE = EVIDENCE_DIR / "Anti_Patterns" / "anti_patterns_active.json"

# Log line format: [YYYY-MM-DD HH:MM:SS] ROLE: text | SIG: hash
_LOG_LINE_RE = re.compile(
    r"^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] (USER|CLAUDE|GEMINI|CODEX|GROK): (.+?)(?:\s*\| SIG: [a-f0-9]+)?$"
)


def is_business_content(text: str) -> bool:
    """Filter non-technical content (pricing, strategy, marketing)."""
    business_signals = [
        "pricing", "revenue", "competitor", "marketing",
        "sales", "invoice", "customer acquisition",
    ]
    text_lower = text.lower()
    return any(signal in text_lower for signal in business_signals)


def count_similar_wants(wants: list, target: str) -> int:
    """Count WANTS similar to target (word overlap > 0.3)."""
    target_words = set(target.lower().split())
    count = 0
    for w in wants:
        w_words = set(w.get("want", "").lower().split())
        if target_words and w_words:
            overlap = len(target_words & w_words) / len(target_words | w_words)
            if overlap > 0.3:
                count += 1
    return count


def count_similar_dont_wants(dont_wants: list, target: str) -> int:
    """Count DON'T_WANTS similar to target."""
    target_words = set(target.lower().split())
    count = 0
    for dw in dont_wants:
        dw_words = set(dw.get("dont_want", "").lower().split())
        if target_words and dw_words:
            overlap = len(target_words & dw_words) / len(target_words | dw_words)
            if overlap > 0.3:
                count += 1
    return count


def route_to_domain(domain: str, prompt: str, response: str,
                    timestamp: str, session_id: str):
    """Route evidence to domain-specific evidence file."""
    domain_file = EVIDENCE_DIR / f"{domain}_learnings.json"
    data = load_json(domain_file)
    item = {
        "timestamp": timestamp,
        "session_id": session_id,
        "type": "interaction",
        "prompt_summary": redact_pii(prompt[:200]),
        "response_summary": redact_pii(response[:200]) if response else "",
        "domain": domain,
    }
    data.append(item)
    save_json(domain_file, data)


def update_growth_metrics(results: dict):
    """Update growth metrics with capture statistics."""
    metrics = load_json_dict(GROWTH_METRICS)
    cap = metrics.get("auto_capture", {
        "total_captures": 0,
        "total_wants": 0,
        "total_dont_wants": 0,
        "thresholds_hit": 0,
        "synthesis_triggers": 0,
        "last_capture": None,
    })
    cap["total_captures"] = cap.get("total_captures", 0) + 1
    cap["total_wants"] = (
        cap.get("total_wants", 0) + results["wants_stored"]
    )
    cap["total_dont_wants"] = (
        cap.get("total_dont_wants", 0) + results["dont_wants_stored"]
    )
    cap["thresholds_hit"] = (
        cap.get("thresholds_hit", 0) + len(results["thresholds_hit"])
    )
    if results["synthesis_triggered"]:
        cap["synthesis_triggers"] = (
            cap.get("synthesis_triggers", 0) + 1
        )
    cap["last_capture"] = results["timestamp"]
    metrics["auto_capture"] = cap
    save_json(GROWTH_METRICS, metrics)


def batch_capture(capture_fn) -> dict:
    """
    Batch mode: scan agent_sessions.json and current_session.json for
    unprocessed interactions. Populate wants.json/dont_wants.json retroactively.

    Tracks last-processed timestamp to avoid re-processing.

    Args:
        capture_fn: The capture() callable from auto_capture (avoids circular import).
    """
    state_file = EVIDENCE_DIR / ".auto_capture_state.json"
    state = {}
    if state_file.exists():
        try:
            state = json.loads(state_file.read_text(encoding="utf-8"))
        except Exception:
            state = {}

    last_ts = state.get("last_processed", "")
    total_captured = 0

    # Process agent_sessions.json (has learnings as prompts)
    sessions_file = EVIDENCE_DIR / "agent_sessions.json"
    if sessions_file.exists():
        try:
            sessions = json.loads(sessions_file.read_text(encoding="utf-8"))
            if isinstance(sessions, list):
                for session in sessions:
                    ts = session.get("timestamp", "")
                    if ts and ts <= last_ts:
                        continue
                    # Build prompt from learnings + failures
                    parts = []
                    for learn in session.get("learnings", []):
                        parts.append(learn)
                    for fail in session.get("failures", []):
                        parts.append(f"Failure: {fail}")
                    if parts:
                        prompt = ". ".join(parts)
                        capture_fn(prompt, "", session.get("agent", "batch"))
                        total_captured += 1
        except Exception as e:
            log.warning("batch_capture sessions error: %s", e)

    # Process current_session.json (has observations/wants/dont_wants)
    if SESSION_EVIDENCE.exists():
        try:
            items = json.loads(SESSION_EVIDENCE.read_text(encoding="utf-8"))
            if isinstance(items, list):
                for item in items:
                    ts = item.get("timestamp", "")
                    if ts and ts <= last_ts:
                        continue
                    desc = item.get("description", "")
                    if desc and len(desc) > 10:
                        capture_fn(desc, "", "batch")
                        total_captured += 1
        except Exception as e:
            log.warning("batch_capture evidence error: %s", e)

    # Update state
    now = datetime.now(timezone.utc).isoformat()
    state["last_processed"] = now
    state["last_batch_count"] = total_captured
    state_file.parent.mkdir(parents=True, exist_ok=True)
    state_file.write_text(json.dumps(state, indent=2), encoding="utf-8")

    log.info("Batch capture complete: %d interactions processed", total_captured)
    return {"status": "ok", "captured": total_captured, "timestamp": now}


def batch_capture_from_log(log_path: str, capture_fn) -> dict:
    """
    Batch mode: parse a pulse_captured_*.log file and extract
    wants/dont_wants from USER+AGENT conversation pairs.

    Log format: [YYYY-MM-DD HH:MM:SS] ROLE: text | SIG: hash

    Pairs consecutive USER->AGENT lines and feeds through capture().
    Tracks last-processed timestamp per log file to avoid re-processing.

    Args:
        log_path: Path to the log file.
        capture_fn: The capture() callable from auto_capture (avoids circular import).
    """
    log_file = Path(log_path)
    if not log_file.exists():
        log.warning("Log file not found: %s", log_path)
        return {"status": "error", "reason": "file not found"}

    # Track state per log file
    state_file = EVIDENCE_DIR / ".auto_capture_state.json"
    state = {}
    if state_file.exists():
        try:
            state = json.loads(state_file.read_text(encoding="utf-8"))
        except Exception:
            state = {}

    log_key = f"log:{log_file.name}"
    last_line_num = state.get(log_key, 0)

    lines = log_file.read_text(encoding="utf-8", errors="replace").splitlines()
    total_lines = len(lines)
    total_captured = 0
    total_wants = 0
    total_dont_wants = 0

    # Parse into (timestamp, role, text) tuples
    parsed_entries = []
    for i, line in enumerate(lines):
        if i < last_line_num:
            continue
        m = _LOG_LINE_RE.match(line.strip())
        if m:
            parsed_entries.append((i, m.group(1), m.group(2), m.group(3).strip()))

    # Pair USER prompts with the next AGENT response
    i = 0
    while i < len(parsed_entries):
        line_num, ts, role, text = parsed_entries[i]
        if role == "USER":
            # Look for agent response in next entry
            agent_text = ""
            agent_role = "batch"
            if i + 1 < len(parsed_entries):
                next_line, next_ts, next_role, next_text = parsed_entries[i + 1]
                if next_role != "USER":
                    agent_text = next_text
                    agent_role = next_role.lower()
                    i += 1  # skip agent line

            # Determine session_id from log filename
            session_id = log_file.stem.replace("pulse_captured_", "") or "batch"

            result = capture_fn(text, agent_text, f"{session_id}_{agent_role}")
            if result.get("status") != "skipped":
                total_captured += 1
                total_wants += result.get("wants_stored", 0)
                total_dont_wants += result.get("dont_wants_stored", 0)
        i += 1

    # Update state
    now = datetime.now(timezone.utc).isoformat()
    state[log_key] = total_lines
    state["last_log_batch"] = now
    state["last_log_file"] = str(log_file.name)
    state_file.parent.mkdir(parents=True, exist_ok=True)
    state_file.write_text(json.dumps(state, indent=2), encoding="utf-8")

    log.info(
        "Log batch complete: %s — %d lines, %d captured, %d wants, %d dont_wants",
        log_file.name, total_lines - last_line_num, total_captured,
        total_wants, total_dont_wants,
    )
    return {
        "status": "ok",
        "file": str(log_file.name),
        "lines_processed": total_lines - last_line_num,
        "captured": total_captured,
        "wants": total_wants,
        "dont_wants": total_dont_wants,
        "timestamp": now,
    }
