#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""
Clean Intents Batch 1 — PULSE Brain Cleaning Task

Distills the first 80 raw want entries into clean, actionable preferences.
Removes duplicates, fragments, and noise. Keeps architectural rules and prohibitions.

Usage:
    python -m pulse.admin.retroactive.clean_intents_batch1
"""
from __future__ import annotations

import io
import json
import os
import shutil
import sys
from datetime import datetime, timezone
from pathlib import Path

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

if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

if os.name == "nt" and __name__ == "__main__":
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace", line_buffering=True)
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace", line_buffering=True)

from pulse.core.llm_router import dispatch, extract_json

# === CONFIG ===

INTENTS_DIR = ROOT_DIR / "Hippocampus" / "Evidence" / "Intents"
WANTS_FILE = INTENTS_DIR / "wants.json"
BATCH_NUM = 1
BATCH_SIZE = 80

# === PROMPT ===

WANTS_PROMPT = """You are the PULSE Intent Purifier. You receive a batch of raw "wants" (user/system preferences) extracted from chat logs. Many are noisy, duplicated, or fragments.

YOUR TASK: Distill into ONLY actionable, clear, unique system preferences.

REMOVE:
- Exact and near-duplicate entries (keep the best-worded version)
- Conversational fragments under 15 characters ("a new flag", "more tests")
- Code snippets or file path fragments
- Task-specific requests that aren't reusable preferences ("fix the bug in line 42")
- Contradictions (keep the most recent/explicit version)

KEEP:
- Clear architectural preferences ("Always use absolute imports")
- System behavior rules ("Never auto-commit without user confirmation")
- Tool/workflow preferences ("Use PowerShell on Windows, not bash")
- Quality standards ("All API endpoints must have error handling")

OUTPUT: Strict JSON array of cleaned want strings. No duplicates. Each must be a complete, actionable sentence.
Example: ["Always use UTF-8 encoding for file operations on Windows", "Never use sys.exit() in library code"]

If NO valid wants exist in this batch, return: []

Here are the raw wants:
"""


# === CORE LOGIC ===


def load_json_file(path: Path) -> list:
    """Load JSON file with error handling."""
    if not path.exists():
        return []
    return json.loads(path.read_text(encoding="utf-8"))


def extract_text_values(entries: list, key: str) -> list[str]:
    """Extract text values from a list of dicts by key."""
    return [e.get(key, "") for e in entries if isinstance(e, dict) and e.get(key)]


def clean_batch1_wants(entries: list) -> list[str]:
    """Send batch 1 entries through LLM, return cleaned results."""
    if not entries:
        print(f"  [wants batch 1] No entries to clean")
        return []

    texts = extract_text_values(entries, "want")
    print(f"  [wants batch 1] {len(texts)} raw entries -> sending to LLM...")

    batch_text = json.dumps(texts, indent=None)
    prompt = WANTS_PROMPT + batch_text

    try:
        raw = dispatch(prompt, task_type="fast")
        # Parse the response — expect a JSON array
        parsed = extract_json(raw)
        if isinstance(parsed, list):
            clean_items = parsed
        elif isinstance(parsed, dict):
            # LLM might wrap in a dict
            clean_items = parsed.get("wants", parsed.get("want", []))
            if not isinstance(clean_items, list):
                clean_items = []
        else:
            clean_items = []

        # Filter: must be strings, >= 15 chars
        clean_items = [s.strip() for s in clean_items if isinstance(s, str) and len(s.strip()) >= 15]

        # Global dedup (case-insensitive)
        seen = set()
        deduped = []
        for item in clean_items:
            key_lower = item.lower().strip()
            if key_lower not in seen:
                seen.add(key_lower)
                deduped.append(item)

        print(f"  [wants batch 1] Result: {len(texts)} -> {len(clean_items)} clean -> {len(deduped)} deduped")
        return deduped

    except Exception as e:
        print(f"  [wants batch 1] ERROR: {e}")
        raise


def rebuild_wants_json(clean_wants: list[str], original_total: int) -> list[dict]:
    """Rebuild wants.json with batch 1 cleaned entries + remaining unchanged."""
    ts = datetime.now(timezone.utc).isoformat()
    rebuilt = []

    # Add cleaned batch 1 entries
    for w in clean_wants:
        rebuilt.append({
            "want": w,
            "priority": 7,
            "domain": "general",
            "visibility": "public",
            "timestamp": ts,
            "source": "llm_cleaned",
            "session_id": "intents_cleaner_batch1",
        })

    return rebuilt


# === MAIN ===


def main():
    print("=" * 60)
    print(f"PULSE — Clean Intents Batch {BATCH_NUM} ({BATCH_SIZE} entries)")
    print("=" * 60)
    print()

    # Load original wants
    print(f"[1/3] Loading wants.json...")
    wants_data = load_json_file(WANTS_FILE)
    print(f"  Total entries: {len(wants_data)}")

    # Extract batch 1
    batch1_entries = wants_data[:BATCH_SIZE]
    print(f"  Batch 1 entries: {len(batch1_entries)}")
    print()

    # Archive original
    print(f"[2/3] Archiving original wants.json...")
    ts = datetime.now().strftime("%Y%m%d_%H%M%S")
    bak = WANTS_FILE.with_suffix(f".pre_batch{BATCH_NUM}_clean_{ts}.json")
    shutil.copy2(WANTS_FILE, bak)
    print(f"  Archived: {bak.name}")
    print()

    # Clean batch 1
    print(f"[3/3] Cleaning batch {BATCH_NUM} entries...")
    clean_wants = clean_batch1_wants(batch1_entries)
    print()

    # Rebuild: cleaned batch 1 + remaining entries
    print("Writing cleaned file...")
    rebuilt_wants = rebuild_wants_json(clean_wants, len(wants_data))

    # Keep remaining entries (batch 2+) from original
    remaining = wants_data[BATCH_SIZE:]
    final_wants = rebuilt_wants + remaining

    WANTS_FILE.write_text(
        json.dumps(final_wants, indent=2, ensure_ascii=False),
        encoding="utf-8",
    )
    print(f"  wants.json: {len(final_wants)} total entries")
    print(f"    - Batch 1 cleaned: {len(clean_wants)} entries")
    print(f"    - Remaining: {len(remaining)} entries (unchanged)")
    print()

    # Summary
    print(f"{'=' * 60}")
    print("SUMMARY")
    print(f"  Original batch 1: {len(batch1_entries)} entries")
    print(f"  Cleaned batch 1:  {len(clean_wants)} entries")
    print(f"  Reduction:        {len(batch1_entries) - len(clean_wants)} removed ({100 * (len(batch1_entries) - len(clean_wants)) // len(batch1_entries) if batch1_entries else 0}%)")
    print(f"{'=' * 60}")


if __name__ == "__main__":
    main()
