#!/usr/bin/env python3
"""
One-shot migration: Hippocampus JSON files -> SQLite
Tasks 1-4: reflex_patterns, wants, dont_wants, strategic_intents, curricula

Run: python pulse/admin/setup/migrate_remaining_json.py
"""
import sys
import json
import hashlib
from pathlib import Path
from datetime import datetime, timezone

ROOT_DIR = Path(__file__).resolve().parents[3]
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

from pulse.core.brain_db import get_conn, init_db, insert_knowledge
from pulse.core.brain_utils import ANTI_PATTERNS_DIR, INTENTS_DIR, KNOWLEDGE_DIR

# ── paths ────────────────────────────────────────────────────────────────────
REFLEX_FILE        = ANTI_PATTERNS_DIR / "reflex_patterns.json"
WANTS_FILE         = INTENTS_DIR / "wants.json"
DONT_WANTS_FILE    = INTENTS_DIR / "dont_wants.json"
STRATEGIC_FILE     = INTENTS_DIR / "strategic_intents.json"
CURRICULA_FILE     = KNOWLEDGE_DIR / "curricula.json"

NOW = datetime.now(timezone.utc).isoformat()


# ── helpers ───────────────────────────────────────────────────────────────────
def _fp(text: str) -> str:
    return hashlib.md5(text.encode("utf-8", errors="replace")).hexdigest()


def _insert_anti_pattern(conn, row: dict) -> bool:
    """Direct insert into anti_patterns table (custom schema)."""
    pid   = row.get("id") or f"RX-{_fp(row.get('description',''))[:8]}"
    desc  = (row.get("description") or "")[:500]
    rule  = row.get("pattern_name", "")
    reason = row.get("pattern_type", "")
    domain = row.get("domain", "general")
    kw    = json.dumps([])
    sev   = row.get("severity", "medium")
    ev    = 1
    status = row.get("status", "active")
    source = row.get("source_agent", "reflex_arc")
    created = row.get("timestamp", NOW)
    meta  = json.dumps({
        "confidence":    row.get("confidence", 0.75),
        "pattern_type":  row.get("pattern_type", ""),
        "pattern_name":  row.get("pattern_name", ""),
        "_hash":         row.get("_hash", ""),
    })
    try:
        with conn:
            conn.execute(
                """INSERT OR IGNORE INTO anti_patterns
                   (id, description, rule, reason, domain, keywords,
                    severity, evidence_count, status, source, created, metadata)
                   VALUES (?,?,?,?,?,?,?,?,?,?,?,?)""",
                (pid, desc, rule, reason, domain, kw,
                 sev, ev, status, source, created, meta)
            )
            changed = conn.execute("SELECT changes()").fetchone()[0]
            if changed > 0:
                conn.execute(
                    """INSERT INTO knowledge_fts
                       (item_id, content, title, domain, agent, table_name)
                       VALUES (?,?,?,?,?,?)""",
                    (pid, desc, rule, domain, source, "anti_patterns")
                )
        return changed > 0
    except Exception as e:
        print(f"  [warn] anti_pattern insert error ({pid}): {e}")
        return False


def _insert_intent(data: dict, intent_type: str) -> bool:
    """Insert one want/dont_want/strategic_intent into intents table."""
    if intent_type == "want":
        raw_content = data.get("want", "")
    elif intent_type == "dont_want":
        raw_content = data.get("dont_want", "")
    else:  # strategic_intent
        raw_content = data.get("description") or data.get("title") or str(data)[:300]

    content = (raw_content or "").strip()
    if len(content) < 15:
        return False

    # salience/priority may be None — treat None as 1.0
    raw_sal = data.get("salience") or data.get("priority")
    try:
        salience = float(raw_sal) if raw_sal is not None else 1.0
    except (TypeError, ValueError):
        salience = 1.0

    # Skip noise: only apply the priority==1 filter to WANTS (not dont_wants/strategic)
    # dont_wants are valuable regardless of priority (audit confirmed all have priority=None)
    if intent_type == "want" and salience == 1.0:
        return False

    raw_conf = data.get("confidence")
    try:
        confidence = float(raw_conf) if raw_conf is not None else 0.6
    except (TypeError, ValueError):
        confidence = 0.6

    row = {
        "content":    content,
        "type":       intent_type,
        "domain":     data.get("domain", "general"),
        "agent":      data.get("_agent_id") or data.get("source_agent") or "auto_capture",
        "timestamp":  data.get("timestamp", NOW),
        "salience":   salience,
        "confidence": confidence,
        "metadata":   {k: v for k, v in data.items()
                       if k not in ("want", "dont_want", "description",
                                    "salience", "confidence", "domain",
                                    "timestamp", "_agent_id")},
    }
    try:
        insert_knowledge("intents", row)
        return True
    except Exception as e:
        print(f"  [warn] intent insert error: {e}")
        return False


def _insert_curriculum(conn, key: str, val: dict) -> bool:
    """Insert one curriculum entry into schemas table."""
    cid   = f"CUR-{_fp(key)[:8]}"
    name  = key[:120]
    desc  = json.dumps(val)[:2000]  # store the whole struct as description
    domain = val.get("domain", "general")
    conf  = float(val.get("stats", {}).get("avg_success_rate", 0.5))
    created = val.get("created", NOW)
    meta  = json.dumps({"generation": val.get("generation", 1)})
    try:
        with conn:
            conn.execute(
                """INSERT OR IGNORE INTO schemas
                   (id, name, description, domain, confidence, type,
                    source, evidence_links, created, metadata)
                   VALUES (?,?,?,?,?,?,?,?,?,?)""",
                (cid, name, desc, domain, conf, "curriculum",
                 "curricula.json", "[]", created, meta)
            )
            changed = conn.execute("SELECT changes()").fetchone()[0]
            if changed > 0:
                conn.execute(
                    """INSERT INTO knowledge_fts
                       (item_id, content, title, domain, agent, table_name)
                       VALUES (?,?,?,?,?,?)""",
                    (cid, desc[:500], name, domain, "curricula", "schemas")
                )
        return changed > 0
    except Exception as e:
        print(f"  [warn] curriculum insert error ({key}): {e}")
        return False


# ── Task 1: reflex_patterns.json -> anti_patterns ─────────────────────────────
def migrate_reflex(conn) -> int:
    if not REFLEX_FILE.exists():
        print(f"  [skip] {REFLEX_FILE} not found")
        return 0
    raw = json.loads(REFLEX_FILE.read_text(encoding="utf-8"))
    entries = raw.get("entries", raw) if isinstance(raw, dict) else raw
    ok = sum(_insert_anti_pattern(conn, e) for e in entries)
    print(f"  -> {ok}/{len(entries)} reflex patterns inserted (skipped duplicates)")
    return ok


# ── Task 2: wants + dont_wants -> intents ────────────────────────────────────
def _migrate_intent_file(path: Path, intent_type: str) -> int:
    if not path.exists():
        print(f"  [skip] {path} not found")
        return 0
    data = json.loads(path.read_text(encoding="utf-8"))
    entries = data if isinstance(data, list) else data.get("entries", [])
    ok = sum(_insert_intent(e, intent_type) for e in entries)
    print(f"  -> {ok}/{len(entries)} {intent_type} inserted")
    return ok


# ── Task 3: strategic_intents.json -> intents ─────────────────────────────────
def migrate_strategic_intents() -> int:
    if not STRATEGIC_FILE.exists():
        print(f"  [skip] {STRATEGIC_FILE} not found")
        return 0
    raw = json.loads(STRATEGIC_FILE.read_text(encoding="utf-8"))
    intents = raw.get("intents", raw) if isinstance(raw, dict) else raw
    if isinstance(intents, dict):
        intents = list(intents.values())
    ok = 0
    for item in intents:
        if isinstance(item, dict):
            item["type"] = "strategic_intent"
            ok += _insert_intent(item, "strategic_intent")
        elif isinstance(item, str) and len(item) >= 15:
            ok += _insert_intent({"description": item, "salience": 5.0}, "strategic_intent")
    print(f"  -> {ok}/{len(intents)} strategic intents inserted")
    return ok


# ── Task 4: curricula.json -> schemas ─────────────────────────────────────────
def migrate_curricula(conn) -> int:
    if not CURRICULA_FILE.exists():
        print(f"  [skip] {CURRICULA_FILE} not found")
        return 0
    raw = json.loads(CURRICULA_FILE.read_text(encoding="utf-8"))
    curricula = raw.get("curricula", raw) if isinstance(raw, dict) else raw
    if isinstance(curricula, list):
        items = {str(i): v for i, v in enumerate(curricula)}
    else:
        items = curricula
    ok = sum(_insert_curriculum(conn, k, v) for k, v in items.items())
    print(f"  -> {ok}/{len(items)} curricula inserted")
    return ok


# ── main ──────────────────────────────────────────────────────────────────────
def main():
    print("Initializing DB...")
    init_db()
    conn = get_conn()

    print("\nTask 1: reflex_patterns -> anti_patterns")
    migrate_reflex(conn)

    print("\nTask 2: wants -> intents")
    _migrate_intent_file(WANTS_FILE, "want")

    print("\nTask 2b: dont_wants -> intents")
    _migrate_intent_file(DONT_WANTS_FILE, "dont_want")

    print("\nTask 3: strategic_intents -> intents")
    migrate_strategic_intents()

    print("\nTask 4: curricula -> schemas")
    migrate_curricula(conn)

    # Print final counts
    conn2 = get_conn()
    for tbl in ("anti_patterns", "intents", "schemas"):
        n = conn2.execute(f"SELECT COUNT(*) FROM {tbl}").fetchone()[0]
        print(f"\n  [{tbl}] total rows: {n}")

    print("\nMigration complete.")


if __name__ == "__main__":
    main()
