"""Middleware configuration management.

Loads middleware config from layered YAML files:
  1. Global defaults: ~/.omni-cortex/middleware.yaml
  2. Project overrides: .omni-cortex/middleware.yaml

Project values override global. Missing files or malformed YAML
return safe defaults (fail-open design).
"""

import os
import sys
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional

try:
    import yaml
except ImportError:
    yaml = None


@dataclass
class CacheConfig:
    """Cache layer configuration."""

    enabled: bool = True
    verbose: bool = False
    ttl: dict = field(default_factory=lambda: {
        "Read": 300,
        "Grep": 300,
        "Glob": 600,
        "WebFetch": 1800,
    })
    max_cached_response_size: int = 4000
    whitelist: list = field(default_factory=lambda: [
        "Read", "Grep", "Glob", "WebFetch"
    ])


@dataclass
class MiddlewareConfig:
    """Top-level middleware configuration."""

    enabled: bool = True
    verbose: bool = False
    cache: CacheConfig = field(default_factory=CacheConfig)


def _deep_merge(base: dict, override: dict) -> dict:
    """Deep-merge override into base. Scalars are replaced, dicts are merged recursively."""
    result = base.copy()
    for key, value in override.items():
        if key in result and isinstance(result[key], dict) and isinstance(value, dict):
            result[key] = _deep_merge(result[key], value)
        else:
            result[key] = value
    return result


def _parse_cache_config(data: dict) -> CacheConfig:
    """Parse cache section into CacheConfig dataclass."""
    defaults = CacheConfig()
    return CacheConfig(
        enabled=data.get("enabled", defaults.enabled),
        verbose=data.get("verbose", defaults.verbose),
        ttl=data.get("ttl", defaults.ttl),
        max_cached_response_size=data.get("max_cached_response_size", defaults.max_cached_response_size),
        whitelist=data.get("whitelist", defaults.whitelist),
    )


def _load_yaml_file(path: Path) -> Optional[dict]:
    """Load a YAML file, returning None on any error."""
    if yaml is None:
        return None
    if not path.exists():
        return None
    try:
        with open(path, "r") as f:
            data = yaml.safe_load(f)
            return data if isinstance(data, dict) else None
    except Exception as e:
        print(f"[middleware] Warning: failed to load {path}: {e}", file=sys.stderr)
        return None


def load_middleware_config(project_path: Optional[str] = None) -> MiddlewareConfig:
    """Load middleware configuration with layered merging.

    Priority: project middleware.yaml > global middleware.yaml > defaults

    Args:
        project_path: Project directory path. If None, uses CLAUDE_PROJECT_DIR or cwd.

    Returns:
        MiddlewareConfig with merged settings. Always returns valid config (fail-open).
    """
    if project_path is None:
        project_path = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())

    # Load global config
    global_path = Path.home() / ".omni-cortex" / "middleware.yaml"
    global_data = _load_yaml_file(global_path)

    # Load project config
    project_config_path = Path(project_path) / ".omni-cortex" / "middleware.yaml"
    project_data = _load_yaml_file(project_config_path)

    # Merge: start with empty, apply global, then project
    merged = {}
    if global_data:
        # Config can be wrapped in a 'middleware:' key or flat
        merged = global_data.get("middleware", global_data)
    if project_data:
        override = project_data.get("middleware", project_data)
        merged = _deep_merge(merged, override) if merged else override

    # No config files found — return defaults
    if not merged:
        return MiddlewareConfig()

    # Parse into dataclass
    try:
        cache_data = merged.get("cache", {})
        cache_config = _parse_cache_config(cache_data) if isinstance(cache_data, dict) else CacheConfig()

        return MiddlewareConfig(
            enabled=merged.get("enabled", True),
            verbose=merged.get("verbose", False),
            cache=cache_config,
        )
    except Exception as e:
        print(f"[middleware] Warning: config parse error, using defaults: {e}", file=sys.stderr)
        return MiddlewareConfig()
