#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
PULSE API — Brain router. Endpoints for brain data (lessons, failures, patterns, graph, etc).
"""
from __future__ import annotations

import sys
from pathlib import Path
from fastapi import APIRouter, HTTPException, Request

from pulse.core.pii_filter import redact_pii

SCRIPT_DIR = Path(__file__).resolve().parent
ROOT_DIR = SCRIPT_DIR.parent.parent
TOOLS_DIR = ROOT_DIR / "pulse" / "brain"
HIPPOCAMPUS = ROOT_DIR / "Hippocampus"


router = APIRouter(prefix="/v1/brain", tags=["brain"])


def _read_md_items(filepath: Path) -> list[str]:
    """Read markdown file and return section-based items.

    Each ## heading starts a new item. The body text (excluding metadata
    lines like **Source:** and **Salience:**) forms the item content.
    """
    if not filepath.exists():
        return []
    text = filepath.read_text(encoding="utf-8", errors="replace")
    # Split on ## headings
    sections = text.split("\n## ")
    items = []
    for i, section in enumerate(sections):
        if i == 0:
            continue  # skip preamble (front-matter, # title, etc.)
        # First line is the heading, rest is body
        lines = section.strip().splitlines()
        body_lines = []
        for ln in lines[1:]:  # skip heading line
            stripped = ln.strip()
            if not stripped or stripped == "---" or stripped.startswith(">"):
                continue
            if stripped.startswith("**Source:**") or stripped.startswith("**Salience:**"):
                continue
            body_lines.append(stripped)
        if body_lines:
            items.append(redact_pii(" ".join(body_lines)[:500]))
    return items


def _paginate(items: list, offset: int = 0, limit: int = 200) -> tuple[list, int]:
    """Return a page of items and total count."""
    total = len(items)
    return items[offset:offset + limit], total


@router.get("/lessons")
async def get_lessons(offset: int = 0, limit: int = 200):
    """Return brain lessons (paginated)."""
    all_items = _read_md_items(HIPPOCAMPUS / "Lessons" / "auto_lessons.md")
    items, total = _paginate(all_items, offset, limit)
    return {"count": total, "offset": offset, "limit": limit, "lessons": items}


@router.get("/failures")
async def get_failures(offset: int = 0, limit: int = 200):
    """Return brain failures (paginated)."""
    all_items = _read_md_items(HIPPOCAMPUS / "Failures" / "auto_fails.md")
    items, total = _paginate(all_items, offset, limit)
    return {"count": total, "offset": offset, "limit": limit, "failures": items}


@router.get("/patterns")
async def get_patterns(offset: int = 0, limit: int = 200):
    """Return brain patterns (paginated)."""
    all_items = _read_md_items(HIPPOCAMPUS / "Patterns" / "auto_patterns.md")
    items, total = _paginate(all_items, offset, limit)
    return {"count": total, "offset": offset, "limit": limit, "patterns": items}


@router.get("/graph")
async def get_graph():
    """Return knowledge graph summary."""
    graph_file = HIPPOCAMPUS / "Knowledge" / "knowledge_graph.json"
    if not graph_file.exists():
        return {"nodes": 0, "edges": 0, "data": {}}
    import json
    data = json.loads(graph_file.read_text(encoding="utf-8"))
    return {
        "nodes": len(data.get("nodes", [])),
        "edges": len(data.get("edges", [])),
        "data": data,
    }


@router.get("/search")
async def search_brain(q: str = ""):
    """Search brain for a query string."""
    if not q or len(q) < 2:
        raise HTTPException(status_code=400, detail="Query 'q' must be at least 2 characters.")
    try:
        import subprocess
        result = subprocess.run(
            [sys.executable, str(TOOLS_DIR / "brain_search.py"), q, "--json", "--exclude-private"],
            capture_output=True, timeout=15, cwd=str(ROOT_DIR),
        )
        stdout = result.stdout.decode("utf-8", errors="replace") if isinstance(result.stdout, bytes) else result.stdout
        if result.returncode == 0 and stdout.strip():
            import json
            # stdout has banner text before JSON — extract the JSON object
            json_start = stdout.find("{")
            if json_start >= 0:
                return json.loads(stdout[json_start:])
        return {"query": q, "results": [], "raw": stdout[:2000]}
    except Exception as e:
        return {"query": q, "results": [], "error": str(e)}


def _read_json_list(filepath: Path, key: str | None = None) -> list:
    """Read a JSON file and return its list contents.
    If key is provided and data is a dict, extract data[key]."""
    if not filepath.exists():
        return []
    import json
    try:
        data = json.loads(filepath.read_text(encoding="utf-8"))
        if isinstance(data, list):
            return data
        if isinstance(data, dict) and key:
            items = data.get(key, [])
            return items if isinstance(items, list) else []
        return []
    except Exception:
        return []


@router.get("/schemas")
async def get_schemas():
    """Return domain schemas extracted by the schema daemon."""
    items = _read_json_list(HIPPOCAMPUS / "Patterns" / "schemas.json", key="schemas")
    return {"count": len(items), "schemas": items}


@router.get("/procedures")
async def get_procedures():
    """Return procedures extracted by the procedure daemon."""
    items = _read_json_list(HIPPOCAMPUS / "Evidence" / "Metrics" / "procedural_log.json", key="procedures")
    return {"count": len(items), "procedures": items}


@router.get("/wants")
async def get_wants():
    """Return wants from intents tracking."""
    items = _read_json_list(HIPPOCAMPUS / "Evidence" / "Intents" / "wants.json")
    return {"count": len(items), "wants": items}


@router.get("/dont_wants")
async def get_dont_wants():
    """Return dont_wants from intents tracking."""
    items = _read_json_list(HIPPOCAMPUS / "Evidence" / "Intents" / "dont_wants.json")
    return {"count": len(items), "dont_wants": items}


@router.get("/strategic_intents")
async def get_strategic_intents():
    """Return strategic intents."""
    items = _read_json_list(HIPPOCAMPUS / "Evidence" / "Intents" / "strategic_intents.json", key="intents")
    return {"count": len(items), "strategic_intents": items}


@router.get("/anti_patterns")
async def get_anti_patterns():
    """Return active anti-patterns."""
    items = _read_json_list(HIPPOCAMPUS / "Evidence" / "Anti_Patterns" / "anti_patterns_active.json")
    return {"count": len(items), "anti_patterns": items}
