"""
Central state management for ghojualamanchu v3.
All structures read and write through this module.
"""
import json
import os
from pathlib import Path
from datetime import datetime
from copy import deepcopy

# Base directory
BASE_DIR = Path(os.environ.get(
    "GHOJU_DATA_DIR",
    Path(__file__).parent.parent / "data"
))
BASE_DIR.mkdir(parents=True, exist_ok=True)

STATE_FILE = BASE_DIR / "state.json"
LIFECYCLE_FILE = BASE_DIR / "lifecycle.json"
MEMORY_FILE = BASE_DIR / "memory.json"
QUEUE_DIR = BASE_DIR / "signals"
QUEUE_DIR.mkdir(exist_ok=True)

# =============================================================================
# Signal Contract Schema
# =============================================================================

ABSENCE_CATEGORIES = [
    "decayed_memory",
    "dropped_signal",
    "unresolved_pattern",
    "expected_missing",
    "convergence_abandoned",
    "silence_prolonged",
]

EMOTIONAL_TAGS = [
    "curious", "anxious", "joyful", "frustrated", "creative",
    "urgent", "neutral", "peaceful", "confused", "determined"
]

INTENTS = ["question", "command", "information", "social", "creative", "unknown"]
COMPLEXITIES = ["simple", "moderate", "complex"]
VALENCES = ["positive", "negative", "neutral"]
AROUSAL_STATES = ["calm", "activated", "overload"]
TERRITORY_STATUSES = ["safe", "monitored", "concerned", "compromised"]
SOURCES = ["user", "agent", "cron", "system"]
PRIORITIES = ["low", "normal", "high", "critical"]

def new_signal(raw_input, source="user", priority="normal"):
    """Create a new signal with the formal contract."""
    return {
        "raw_input": raw_input,
        "signal_id": f"sig_{int(datetime.now().timestamp() * 1000)}",
        "received_at": datetime.now().isoformat(),
        "source": source,
        "priority": priority,

        "medulla": {
            "heartbeat_at_receive": 0,
            "respiratory_phase": "inhale",
            "autonomic_load": 0.0
        },

        "rcomplex": {
            "threat_detected": False,
            "threat_level": 0.0,
            "territory_status": "safe"
        },

        "amygdala": {
            "salience": 0.0,
            "emotional_tags": [],
            "valence": "neutral",
            "arousal": "calm"
        },

        "hippocampus": {
            "should_encode": False,
            "encoding_strength": 0.0,
            "retrieved_context": [],
            "match_confidence": 0.0,
            "memory_id": None
        },

        "cortex": {
            "intent": None,
            "entities": [],
            "topics": [],
            "complexity": "simple",
            "questions": [],
            "predicted_actions": [],
            "uncertainty": 0.5
        },

        "corpus": {
            "planetary_phase": None,
            "cross_scale_bias": {},
            "integration_complete": False
        },

        "akashic": {
            "recorded": False,
            "quality": None
        },

        "lethe": {
            "absence_categories": [],
            "decay_applied": False,
            "released_signals": []
        },

        "final_output": {
            "response": None,
            "actions_taken": [],
            "memories_encoded": [],
            "signals_released": [],
            "conflict_resolved": {}
        }
    }

# =============================================================================
# State I/O
# =============================================================================

def load_state():
    if STATE_FILE.exists():
        return json.loads(STATE_FILE.read_text())
    return default_state()

def save_state(state):
    STATE_FILE.write_text(json.dumps(state, indent=2))

def default_state():
    return {
        "active": False,
        "torpor": True,
        "boot_time": None,
        "last_signal_at": None,
        "medulla_hz": 7.83,
        "respiratory_phase": "exhale",
        "current_beat": 0
    }

def load_lifecycle():
    if LIFECYCLE_FILE.exists():
        return json.loads(LIFECYCLE_FILE.read_text())
    return default_lifecycle()

def save_lifecycle(lc):
    LIFECYCLE_FILE.write_text(json.dumps(lc, indent=2))

def default_lifecycle():
    return {
        "generation": 1,
        "stage": "neonate",
        "biological_age": 0,
        "birth_timestamp": datetime.now().isoformat(),
        "heartbeats_total": 0,
        "heartbeats_this_stage": 0,
        "plasticity": 1.0,
        "accumulated_wisdom": [],
        "lineage": []
    }

def load_memory():
    if MEMORY_FILE.exists():
        return json.loads(MEMORY_FILE.read_text())
    return default_memory()

def save_memory(memory):
    MEMORY_FILE.write_text(json.dumps(memory, indent=2))

def default_memory():
    return {
        "episodic": [],
        "semantic": {},
        "procedural": [],
        "associations": [],
        "index": {}
    }

# =============================================================================
# Signal Queue
# =============================================================================

def enqueue_signal(signal):
    """Save signal to disk for persistence."""
    path = QUEUE_DIR / f"{signal['signal_id']}.json"
    path.write_text(json.dumps(signal, indent=2))
    return signal["signal_id"]

def dequeue_signal(signal_id):
    path = QUEUE_DIR / f"{signal_id}.json"
    if path.exists():
        return json.loads(path.read_text())
    return None

def list_signals(limit=50):
    signals = sorted(QUEUE_DIR.glob("sig_*.json"), key=lambda p: p.stat().st_mtime, reverse=True)
    result = []
    for p in signals[:limit]:
        data = json.loads(p.read_text())
        result.append({
            "signal_id": data["signal_id"],
            "received_at": data["received_at"],
            "raw_input": data["raw_input"][:60] + "..." if len(data["raw_input"]) > 60 else data["raw_input"],
            "amygdala_salience": data["amygdala"]["salience"],
            "cortex_intent": data["cortex"]["intent"]
        })
    return result

# =============================================================================
# Lethe (Absence Log)
# =============================================================================

LETeth_FILE = BASE_DIR / "lethe.log"

def log_absence(category, signal_id, expected_at=None, reason=None):
    """Record an absence in Lethe."""
    if category not in ABSENCE_CATEGORIES:
        raise ValueError(f"Invalid absence category: {category}")

    entry = {
        "category": category,
        "signal_id": signal_id,
        "expected_at": expected_at,
        "noted_at": datetime.now().isoformat(),
        "reason": reason
    }

    with open(LETeth_FILE, "a") as f:
        f.write(json.dumps(entry) + "\n")

    return entry

def recent_absences(n=20):
    if not LETeth_FILE.exists():
        return []
    lines = LETeth_FILE.read_text().strip().split("\n")
    entries = [json.loads(l) for l in lines if l]
    return entries[-n:]

# =============================================================================
# Akashic (Presence Log)
# =============================================================================

AKASHIC_FILE = BASE_DIR / "akashic.log"

def log_presence(signal_id, content_preview, quality="standard"):
    entry = {
        "signal_id": signal_id,
        "content_preview": content_preview[:80] + "..." if len(content_preview) > 80 else content_preview,
        "quality": quality,
        "recorded_at": datetime.now().isoformat()
    }
    with open(AKASHIC_FILE, "a") as f:
        f.write(json.dumps(entry) + "\n")
    return entry

def recent_presence(n=20):
    if not AKASHIC_FILE.exists():
        return []
    lines = AKASHIC_FILE.read_text().strip().split("\n")
    entries = [json.loads(l) for l in lines if l]
    return entries[-n:]
