"""Configuration management for Mnemosynth.

Handles loading/saving YAML config from ~/.mnemosynth/config.yaml
with environment variable overrides.
"""

from __future__ import annotations

import os
from dataclasses import dataclass, field
from pathlib import Path

import yaml


DEFAULT_DATA_DIR = os.path.expanduser("~/.mnemosynth")


@dataclass
class DecayConfig:
    """Ebbinghaus forgetting curve settings."""
    enabled: bool = True
    half_life_days: float = 30.0
    min_confidence: float = 0.1  # Below this → auto-archive


@dataclass
class ContradictionConfig:
    """NLI-based contradiction detection settings."""
    enabled: bool = True
    model: str = "cross-encoder/nli-deberta-v3-small"
    threshold: float = 0.85


@dataclass
class DreamConfig:
    """Dream mode (background consolidation) settings."""
    auto_schedule: bool = False
    interval_hours: int = 24
    min_cluster_size: int = 3


@dataclass
class DigestConfig:
    """Memory digest compression settings."""
    max_tokens: int = 150
    include_types: list[str] = field(default_factory=lambda: ["episodic", "semantic", "procedural"])
    top_k: int = 5


@dataclass
class SentimentConfig:
    """Emotional memory layer settings."""
    enabled: bool = True
    boost_factor: float = 1.2  # High-emotion memory retrieval boost


@dataclass
class MnemosynthConfig:
    """Master configuration for Mnemosynth."""

    data_dir: str | None = None
    embedding_model: str = "all-MiniLM-L6-v2"
    max_episodic_memories: int = 10000
    max_semantic_nodes: int = 5000

    decay: DecayConfig = field(default_factory=DecayConfig)
    contradiction: ContradictionConfig = field(default_factory=ContradictionConfig)
    dream: DreamConfig = field(default_factory=DreamConfig)
    digest: DigestConfig = field(default_factory=DigestConfig)
    sentiment: SentimentConfig = field(default_factory=SentimentConfig)

    def __post_init__(self):
        # Resolve data directory
        if self.data_dir is None:
            self.data_dir = os.environ.get("MNEMOSYNTH_DATA_DIR", DEFAULT_DATA_DIR)
        self.data_dir = os.path.expanduser(self.data_dir)

        # Load config file if it exists
        config_path = self.config_path
        if config_path.exists():
            self._load_from_yaml(config_path)

    @property
    def config_path(self) -> Path:
        return Path(self.data_dir) / "config.yaml"

    @property
    def db_path(self) -> str:
        return str(Path(self.data_dir) / "memory.db")

    @property
    def vectors_dir(self) -> str:
        return str(Path(self.data_dir) / "vectors")

    @property
    def graph_path(self) -> str:
        return str(Path(self.data_dir) / "graph.db")

    @property
    def procedural_dir(self) -> str:
        return str(Path(self.data_dir) / "procedures")

    def ensure_dirs(self) -> None:
        """Create all necessary directories."""
        Path(self.data_dir).mkdir(parents=True, exist_ok=True)
        Path(self.vectors_dir).mkdir(parents=True, exist_ok=True)
        Path(self.procedural_dir).mkdir(parents=True, exist_ok=True)

    def _load_from_yaml(self, path: Path) -> None:
        """Override defaults with values from config file."""
        try:
            with open(path) as f:
                data = yaml.safe_load(f) or {}
        except Exception:
            return

        # Top-level
        memory_cfg = data.get("memory", {})
        if "data_dir" in memory_cfg:
            self.data_dir = os.path.expanduser(memory_cfg["data_dir"])
        if "embedding_model" in memory_cfg:
            self.embedding_model = memory_cfg["embedding_model"]
        if "max_episodic_memories" in memory_cfg:
            self.max_episodic_memories = memory_cfg["max_episodic_memories"]
        if "max_semantic_nodes" in memory_cfg:
            self.max_semantic_nodes = memory_cfg["max_semantic_nodes"]

        # Decay
        decay_cfg = data.get("decay", {})
        if "enabled" in decay_cfg:
            self.decay.enabled = decay_cfg["enabled"]
        if "half_life_days" in decay_cfg:
            self.decay.half_life_days = decay_cfg["half_life_days"]
        if "min_confidence" in decay_cfg:
            self.decay.min_confidence = decay_cfg["min_confidence"]

        # Contradiction
        contra_cfg = data.get("contradiction", {})
        if "enabled" in contra_cfg:
            self.contradiction.enabled = contra_cfg["enabled"]
        if "model" in contra_cfg:
            self.contradiction.model = contra_cfg["model"]
        if "threshold" in contra_cfg:
            self.contradiction.threshold = contra_cfg["threshold"]

        # Dream
        dream_cfg = data.get("dream", {})
        if "auto_schedule" in dream_cfg:
            self.dream.auto_schedule = dream_cfg["auto_schedule"]
        if "interval_hours" in dream_cfg:
            self.dream.interval_hours = dream_cfg["interval_hours"]
        if "min_cluster_size" in dream_cfg:
            self.dream.min_cluster_size = dream_cfg["min_cluster_size"]

        # Digest
        digest_cfg = data.get("digest", {})
        if "max_tokens" in digest_cfg:
            self.digest.max_tokens = digest_cfg["max_tokens"]
        if "include_types" in digest_cfg:
            self.digest.include_types = digest_cfg["include_types"]

        # Sentiment
        sent_cfg = data.get("sentiment", {})
        if "enabled" in sent_cfg:
            self.sentiment.enabled = sent_cfg["enabled"]
        if "boost_factor" in sent_cfg:
            self.sentiment.boost_factor = sent_cfg["boost_factor"]

    def save(self) -> None:
        """Save current config to YAML file."""
        self.ensure_dirs()
        data = {
            "memory": {
                "data_dir": self.data_dir,
                "embedding_model": self.embedding_model,
                "max_episodic_memories": self.max_episodic_memories,
                "max_semantic_nodes": self.max_semantic_nodes,
            },
            "decay": {
                "enabled": self.decay.enabled,
                "half_life_days": self.decay.half_life_days,
                "min_confidence": self.decay.min_confidence,
            },
            "contradiction": {
                "enabled": self.contradiction.enabled,
                "model": self.contradiction.model,
                "threshold": self.contradiction.threshold,
            },
            "dream": {
                "auto_schedule": self.dream.auto_schedule,
                "interval_hours": self.dream.interval_hours,
                "min_cluster_size": self.dream.min_cluster_size,
            },
            "digest": {
                "max_tokens": self.digest.max_tokens,
                "include_types": self.digest.include_types,
            },
            "sentiment": {
                "enabled": self.sentiment.enabled,
                "boost_factor": self.sentiment.boost_factor,
            },
        }
        with open(self.config_path, "w") as f:
            yaml.dump(data, f, default_flow_style=False, sort_keys=False)
