"""SalmAlm DI Container — Lightweight service registry.

Provides a central registry for all singleton services,
replacing scattered global instances. Supports:
  - Lazy initialization
  - Service replacement (for testing)
  - Type-safe access via properties
  - Startup validation

Usage:
    from salmalm.container import app
    vault = app.vault
    router = app.router
"""

from __future__ import annotations

import threading
from typing import Any, Callable, Dict, Optional, Type, TypeVar

T = TypeVar('T')


class Container:
    """Lightweight DI container with lazy initialization."""

    def __init__(self) -> None:
        self._services: Dict[str, Any] = {}
        self._factories: Dict[str, Callable[[], Any]] = {}
        self._lock = threading.Lock()

    def register(self, name: str, factory: Callable[[], T]) -> None:
        """Register a lazy factory for a service."""
        with self._lock:
            self._factories[name] = factory

    def set(self, name: str, instance: Any) -> None:
        """Set an already-created service instance."""
        with self._lock:
            self._services[name] = instance

    def get(self, name: str) -> Any:
        """Get a service, creating it lazily if needed."""
        if name in self._services:
            return self._services[name]
        with self._lock:
            # Double-check after acquiring lock
            if name in self._services:
                return self._services[name]
            if name in self._factories:
                instance = self._factories[name]()
                self._services[name] = instance
                return instance
        raise KeyError(f"Service not registered: {name}")

    def replace(self, name: str, instance: Any) -> Any:
        """Replace a service (for testing). Returns old instance."""
        with self._lock:
            old = self._services.get(name)
            self._services[name] = instance
            return old

    def has(self, name: str) -> bool:
        return name in self._services or name in self._factories

    def reset(self) -> None:
        """Clear all services (for testing)."""
        with self._lock:
            self._services.clear()
            self._factories.clear()

    # ── Typed properties for IDE autocomplete ────────────────

    @property
    def vault(self) -> 'Vault':
        return self.get('vault')

    @property
    def router(self) -> 'ModelRouter':
        return self.get('router')

    @property
    def auth_manager(self) -> 'AuthManager':
        return self.get('auth_manager')

    @property
    def rate_limiter(self) -> 'RateLimiter':
        return self.get('rate_limiter')

    @property
    def rag_engine(self) -> 'RAGEngine':
        return self.get('rag_engine')

    @property
    def mcp_manager(self) -> 'MCPManager':
        return self.get('mcp_manager')

    @property
    def node_manager(self) -> 'NodeManager':
        return self.get('node_manager')

    @property
    def health_monitor(self) -> 'HealthMonitor':
        return self.get('health_monitor')

    @property
    def telegram_bot(self) -> 'TelegramBot':
        return self.get('telegram_bot')

    @property
    def ws_server(self) -> 'WebSocketServer':
        return self.get('ws_server')

    def validate(self) -> Dict[str, bool]:
        """Check all expected services are registered."""
        expected = [
            'vault', 'router', 'auth_manager', 'rate_limiter',
            'rag_engine', 'mcp_manager', 'node_manager',
            'health_monitor', 'telegram_bot', 'ws_server',
        ]
        return {name: self.has(name) for name in expected}


# ── Global container instance ────────────────────────────────
app = Container()
