#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
Brain Utilities: Shared module for all brain automation daemons (V43.12)

Slim re-exporting hub. Actual logic lives in:
  - brain_io.py       (JSON I/O, file locking, config)
  - brain_analysis.py (text similarity, counting, neuroscience helpers)

This file keeps: path constants, scaffold functions, and re-exports
everything for full backward compatibility.

Dependencies: Python stdlib only (Law 4)
"""

import json
import os
import shutil
import subprocess
from datetime import date, datetime, timezone
from pathlib import Path

# Use the centralized path resolution (Law 4 - SoC)
from pulse.core.paths import get_brain_dir, get_state_dir, get_root_dir

# === PATH CONSTANTS (Flat Hippocampus — 6 regions) ===

ROOT_DIR = get_root_dir()
HIPPOCAMPUS_DIR = get_brain_dir()

# New flat structure (Feb 2026 refactor)
LESSONS_DIR = HIPPOCAMPUS_DIR / "Lessons"
FAILS_DIR = HIPPOCAMPUS_DIR / "Failures"
PATTERNS_DIR = HIPPOCAMPUS_DIR / "Patterns"
EVIDENCE_DIR = HIPPOCAMPUS_DIR / "Evidence"
KNOWLEDGE_DIR = HIPPOCAMPUS_DIR / "Knowledge"
PRIVATE_DIR = HIPPOCAMPUS_DIR / "Private"
ARCHIVE_DIR = HIPPOCAMPUS_DIR / "archive"

# Legacy aliases (for backward compat during transition)
DOMAINS_DIR = KNOWLEDGE_DIR
WINS_DIR = LESSONS_DIR          # Wins merged into Lessons
METADATA_DIR = EVIDENCE_DIR     # Metadata merged into Evidence
WORKING_MEMORY_DIR = EVIDENCE_DIR

# Evidence subdirs (semantic organization)
EVIDENCE_SESSIONS_DIR = EVIDENCE_DIR / "Sessions"
EVIDENCE_DECISIONS_DIR = EVIDENCE_DIR / "Decisions"
EVIDENCE_INTENTS_DIR = EVIDENCE_DIR / "Intents"
EVIDENCE_ANTI_PATTERNS_DIR = EVIDENCE_DIR / "Anti_Patterns"
EVIDENCE_METRICS_DIR = EVIDENCE_DIR / "Metrics"

# Legacy aliases
PRIVATE_EVIDENCE_DIR = PRIVATE_DIR
PRIVATE_PATTERNS_DIR = PRIVATE_DIR
PRIVATE_LESSONS_DIR = PRIVATE_DIR

# Canonical brain files (single source of truth for all writers)
LESSONS_FILE = LESSONS_DIR / "auto_lessons.md"
PATTERNS_FILE = PATTERNS_DIR / "auto_patterns.md"
FAILS_FILE = FAILS_DIR / "auto_fails.md"
DECISIONS_FILE = EVIDENCE_DECISIONS_DIR / "auto_decisions.json"

# Specific files
GROWTH_METRICS = EVIDENCE_METRICS_DIR / "growth_metrics.json"
RETRIEVAL_METRICS = EVIDENCE_METRICS_DIR / "retrieval_metrics.json"
BRAIN_MAP = HIPPOCAMPUS_DIR / "BRAIN_MAP.md"
REFACTOR_LOG = EVIDENCE_DIR / "auto_refactor_log.json"
BENCHMARKS_FILE = EVIDENCE_DIR / "benchmarks.json"
WANTS_FILE = EVIDENCE_DIR / "wants_tracking.json"

# Package subdirectories (code lives in pulse/)
# NOTE: In installed mode, these might be in site-packages, 
# but ROOT_DIR points to project data dir. 
# We need to resolve package paths relative to THIS file.
PKG_ROOT = Path(__file__).resolve().parent.parent  # pulse/
DAEMONS_DIR = PKG_ROOT / "daemons"
AGENTS_DIR = PKG_ROOT / "agents"
WORKERS_DIR = PKG_ROOT / "workers"
BRAIN_TOOLS_DIR = PKG_ROOT / "brain"
TASKS_DIR = PKG_ROOT / "tasks"
ADMIN_DIR = PKG_ROOT / "admin"
CONFIG_DIR = PKG_ROOT / "config"
CONFIG_FILE = CONFIG_DIR / "brain_config.json"

# Non-code paths
# Prefrontal is a user data concept, so it stays in ROOT_DIR
PREFRONTAL_DIR = ROOT_DIR / "Prefrontal_Cortex"
PREFRONTAL_WORKING = PREFRONTAL_DIR / "Working_Memory"
ACTIVE_NEURAL_STATE = PREFRONTAL_WORKING / "ACTIVE_NEURAL_STATE.md"
STATE_DIR = get_state_dir()
ACTION_QUEUE_DIR = PREFRONTAL_DIR / "Action_Queue"
TASK_BOARD_FILE = Path(os.environ.get("PULSE_TASK_BOARD", str(ACTION_QUEUE_DIR / "task_board.json")))
AGENT_REGISTRY_FILE = STATE_DIR / "agent_registry.json"
# Corpus Callosum is user data (Constitution), so ROOT_DIR
PROTOCOL_DIR = ROOT_DIR / "Corpus_Callosum" / "Protocols"
SKILLS_DIR = ROOT_DIR / ".cursor" / "skills"
CONSTITUTION_FILE = ROOT_DIR / "Corpus_Callosum" / "CONSTITUTION.md"

# State files
PID_FILE = STATE_DIR / "pulse_orchestrator.pid"
DAEMON_PIDS_FILE = STATE_DIR / "daemon_pids.json"
WORKER_PIDS_FILE = STATE_DIR / "worker_pids.json"
BRIDGE_STATE_FILE = STATE_DIR / "pulse_bridge_state.json"

# === RE-EXPORTS from brain_io ===
from .brain_io import (  # noqa: F401
    _get_lock, _NoOpLock, _acquire,
    load_json, load_json_dict, save_json, atomic_update_json, load_config,
)

# === RE-EXPORTS from brain_analysis ===
from .brain_analysis import (  # noqa: F401
    text_similarity, search_relevance, extract_domain,
    count_lines, count_json_items, count_md_sections,
    compute_weighted_count, compute_confidence_decay,
    detect_cross_domain_patterns, get_brain_density,
)


# === SHARED UTILITIES ===


def now_iso() -> str:
    """Return current UTC time as ISO 8601 string."""
    return datetime.now(timezone.utc).isoformat()


def load_env(env_file: Path | None = None) -> None:
    """Load .env file into os.environ (skips already-set keys)."""
    path = env_file or (ROOT_DIR / ".env")
    if not path.exists():
        return
    with open(path, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith("#"):
                continue
            if "=" in line:
                key, value = line.split("=", 1)
                value = value.strip()
                if len(value) >= 2 and value[0] == value[-1] and value[0] in ('"', "'"):
                    value = value[1:-1]
                os.environ.setdefault(key.strip(), value)


def is_process_running(pid: int) -> bool:
    """Check if a process is alive (cross-platform)."""
    if os.name == "nt":
        try:
            out = subprocess.check_output(
                ["tasklist", "/FI", f"PID eq {pid}"],
                stderr=subprocess.DEVNULL,
                creationflags=0x08000000,
            ).decode()
            return str(pid) in out
        except Exception:
            return False
    else:
        try:
            os.kill(pid, 0)
            return True
        except OSError:
            return False


# === SCAFFOLD (stays here — uses path constants directly) ===


def _ensure_file(path: Path, content: str):
    if path.exists():
        return
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content, encoding="utf-8")


def _ensure_json(path: Path, is_dict: bool = False):
    default = "{}" if is_dict else "[]"
    _ensure_file(path, default + "\n")


def ensure_brain_scaffold():
    """Ensures all core brain directories and files exist (flat structure)."""
    # 6 Hippocampus regions
    LESSONS_DIR.mkdir(parents=True, exist_ok=True)
    FAILS_DIR.mkdir(parents=True, exist_ok=True)
    PATTERNS_DIR.mkdir(parents=True, exist_ok=True)
    EVIDENCE_DIR.mkdir(parents=True, exist_ok=True)
    KNOWLEDGE_DIR.mkdir(parents=True, exist_ok=True)
    PRIVATE_DIR.mkdir(parents=True, exist_ok=True)
    ARCHIVE_DIR.mkdir(parents=True, exist_ok=True)

    # Evidence subdirs (semantic organization)
    EVIDENCE_SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
    EVIDENCE_DECISIONS_DIR.mkdir(parents=True, exist_ok=True)
    EVIDENCE_INTENTS_DIR.mkdir(parents=True, exist_ok=True)
    EVIDENCE_ANTI_PATTERNS_DIR.mkdir(parents=True, exist_ok=True)
    EVIDENCE_METRICS_DIR.mkdir(parents=True, exist_ok=True)
    # Legacy subdirs
    (EVIDENCE_DIR / "PULSE_System").mkdir(parents=True, exist_ok=True)

    # Non-Hippocampus dirs
    PREFRONTAL_WORKING.mkdir(parents=True, exist_ok=True)
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    STATE_DIR.mkdir(parents=True, exist_ok=True)
    ACTION_QUEUE_DIR.mkdir(parents=True, exist_ok=True)
    (ACTION_QUEUE_DIR / "completed").mkdir(parents=True, exist_ok=True)

    # Core JSON files (lists)
    json_lists = [
        EVIDENCE_SESSIONS_DIR / "current_session.json",
        EVIDENCE_SESSIONS_DIR / "agent_sessions.json",
        EVIDENCE_ANTI_PATTERNS_DIR / "anti_patterns_active.json",
        EVIDENCE_INTENTS_DIR / "wants.json",
        EVIDENCE_INTENTS_DIR / "dont_wants.json",
        PRIVATE_DIR / "private_evidence.json",
        EVIDENCE_DIR / "Anti_Patterns" / "anti_patterns_active.json",
    ]
    for p in json_lists:
        _ensure_json(p, is_dict=False)

    # Core JSON files (dicts)
    json_dicts = [
        TASK_BOARD_FILE,
        AGENT_REGISTRY_FILE,
        EVIDENCE_DECISIONS_DIR / "auto_decisions.json",
        EVIDENCE_INTENTS_DIR / "strategic_intents.json",
        EVIDENCE_METRICS_DIR / "growth_metrics.json",
        CONFIG_DIR / "brain_config.json",
        CONFIG_DIR / "pulse_daemon.json",
        STATE_DIR / "pulse_bridge_state.json",
    ]
    for p in json_dicts:
        _ensure_json(p, is_dict=True)

    # Core markdown files
    md_files = [
        LESSONS_DIR / "auto_lessons.md",
        FAILS_DIR / "auto_fails.md",
        PATTERNS_DIR / "auto_patterns.md",
        PRIVATE_DIR / "private_patterns.md",
        PRIVATE_DIR / "private_lessons.md",
    ]
    for p in md_files:
        _ensure_file(p, "# " + p.stem.replace("_", " ").title() + "\n")

    _ensure_file(ACTIVE_NEURAL_STATE, "# ACTIVE_NEURAL_STATE\n")


# Call to ensure directories/files exist on import
ensure_brain_scaffold()
