#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""Migrate existing Markdown brain files to JSONL format (Phase 1).

Reads auto_lessons.md, auto_fails.md, auto_patterns.md, private_lessons.md
and converts each ## section into a structured JSONL entry with proper
salience scoring (Phase 0 content-aware formula).

Usage:
    python -m pulse.admin.brain_ops.migrate_md_to_jsonl          # dry run
    python -m pulse.admin.brain_ops.migrate_md_to_jsonl --write  # actually write
"""

import re
import sys
from pathlib import Path

ROOT_DIR = Path(__file__).resolve().parent.parent.parent.parent
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

from pulse.core.brain_utils import (
    LESSONS_FILE, FAILS_FILE, PATTERNS_FILE,
    LESSONS_JSONL, FAILS_JSONL, PATTERNS_JSONL, PRIVATE_JSONL,
)
from pulse.core.brain_analysis import compute_item_salience, compute_item_confidence
from pulse.brain.save_writers import build_jsonl_entry, append_knowledge_jsonl

PRIVATE_MD = LESSONS_FILE.parent.parent / "Private" / "private_lessons.md"

# Map: (md_path, jsonl_path, knowledge_type)
MIGRATIONS = [
    (LESSONS_FILE, LESSONS_JSONL, "lesson"),
    (FAILS_FILE, FAILS_JSONL, "failure"),
    (PATTERNS_FILE, PATTERNS_JSONL, "pattern"),
    (PRIVATE_MD, PRIVATE_JSONL, "private"),
]

_META_RE = re.compile(
    r"\*\*Source:\*\*\s*(.+?)\s*\|\s*"
    r"(?:\*\*Domain:\*\*\s*(.+?)\s*\|)?\s*"
    r"(?:\*\*Confidence:\*\*\s*([\d.]+)\s*\|)?\s*"
    r"\*\*Date:\*\*\s*(\S+)"
)
_SALIENCE_RE = re.compile(r"\*\*Salience:\*\*\s*([\d.]+)")
_CC_RE = re.compile(r"\*\*Consolidation Count:\*\*\s*(\d+)")


def parse_md_sections(md_path: Path):
    """Parse a markdown brain file into structured entries."""
    if not md_path.exists():
        return []
    text = md_path.read_text(encoding="utf-8", errors="replace")
    sections = text.split("\n## ")[1:]  # skip header
    entries = []
    for section in sections:
        lines = section.strip().split("\n")
        if not lines:
            continue
        title = lines[0].strip()
        body = "\n".join(lines[1:]).strip()
        if not title or len(title) < 5:
            continue

        # Extract metadata from footer lines
        source = "unknown"
        domain = "general"
        confidence = None
        salience = None
        date_str = ""
        cc = 1

        meta_match = _META_RE.search(body)
        if meta_match:
            source = meta_match.group(1) or "unknown"
            domain = meta_match.group(2) or "general"
            if meta_match.group(3):
                confidence = float(meta_match.group(3))
            date_str = meta_match.group(4) or ""

        sal_match = _SALIENCE_RE.search(body)
        if sal_match:
            salience = float(sal_match.group(1))

        cc_match = _CC_RE.search(body)
        if cc_match:
            cc = int(cc_match.group(1))

        # Strip metadata lines from content
        content_lines = []
        for line in lines[1:]:
            if line.startswith("**Source:**") or line.startswith("**Salience:**"):
                continue
            if line.strip() == "---":
                continue
            content_lines.append(line)
        content = "\n".join(content_lines).strip()
        if not content:
            content = title

        entries.append({
            "title": title,
            "content": content,
            "source": source,
            "domain": domain,
            "confidence": confidence,
            "salience": salience,
            "date": date_str,
            "consolidation_count": cc,
        })
    return entries


def migrate_file(md_path: Path, jsonl_path: Path, knowledge_type: str,
                 write: bool = False) -> dict:
    """Migrate a single MD file to JSONL. Returns stats."""
    entries = parse_md_sections(md_path)
    stats = {"total": len(entries), "written": 0, "skipped_dup": 0, "skipped_short": 0}

    if not entries:
        return stats

    for entry in entries:
        content = entry["content"]
        if len(content) < 15 or len(content.split()) < 3:
            stats["skipped_short"] += 1
            continue

        # Recompute salience with Phase 0 content-aware formula
        sal = compute_item_salience(content, priority=1.0)
        conf = compute_item_confidence(content, source_type="scribe")

        # Preserve original metadata if it was better (manual saves, high-confidence)
        if entry["confidence"] is not None and entry["confidence"] > conf:
            conf = entry["confidence"]
        if entry["salience"] is not None and entry["salience"] > sal:
            # Only keep old salience if it was actually content-calibrated (not the broken 2.0)
            if entry["salience"] != 2.0:
                sal = entry["salience"]

        timestamp = entry["date"] or "2026-01-01"
        if len(timestamp) == 10:
            timestamp += "T00:00:00+00:00"

        jsonl_entry = build_jsonl_entry(
            description=content, source=entry["source"], timestamp=timestamp,
            domain=entry["domain"], confidence=conf, salience=sal,
            knowledge_type=knowledge_type,
            provenance={"migrated_from": md_path.name, "original_salience": entry["salience"],
                        "original_confidence": entry["confidence"]},
        )
        jsonl_entry["consolidation_count"] = entry["consolidation_count"]

        if write:
            written = append_knowledge_jsonl(jsonl_path, jsonl_entry)
            if written:
                stats["written"] += 1
            else:
                stats["skipped_dup"] += 1
        else:
            stats["written"] += 1  # would-write in dry run

    return stats


def main():
    import argparse
    ap = argparse.ArgumentParser(description="Migrate MD brain files to JSONL")
    ap.add_argument("--write", action="store_true", help="Actually write JSONL files")
    args = ap.parse_args()

    mode = "WRITE" if args.write else "DRY RUN"
    print(f"{'=' * 55}")
    print(f"  MD -> JSONL Migration ({mode})")
    print(f"{'=' * 55}")

    grand_total = 0
    for md_path, jsonl_path, ktype in MIGRATIONS:
        if not md_path.exists():
            print(f"\n  [{ktype}] {md_path.name} — not found, skipping")
            continue
        size_kb = md_path.stat().st_size // 1024
        stats = migrate_file(md_path, jsonl_path, ktype, write=args.write)
        grand_total += stats["written"]
        print(f"\n  [{ktype}] {md_path.name} ({size_kb}KB)")
        print(f"    Sections: {stats['total']} | Written: {stats['written']} | "
              f"Dup: {stats['skipped_dup']} | Short: {stats['skipped_short']}")
        if args.write and jsonl_path.exists():
            print(f"    -> {jsonl_path.name} ({jsonl_path.stat().st_size // 1024}KB)")

    print(f"\n{'=' * 55}")
    print(f"  Total: {grand_total} entries {'written' if args.write else 'would write'}")
    print(f"{'=' * 55}")


if __name__ == "__main__":
    main()
