"""Dependency injection container for Hephaestus MCP server."""

from __future__ import annotations

from pathlib import Path
from typing import Any, Dict, Type, TypeVar

T = TypeVar("T")


class DIContainer:
    """Simple dependency injection container."""

    def __init__(self):
        self._services: Dict[str, Any] = {}
        self._factories: Dict[str, callable] = {}
        self._singletons: Dict[str, Any] = {}

    def register(self, service_type: Type[T], implementation: T) -> None:
        """Register a service implementation."""
        key = service_type.__name__
        self._services[key] = implementation

    def register_factory(self, service_type: Type[T], factory: callable) -> None:
        """Register a factory function for lazy loading."""
        key = service_type.__name__
        self._factories[key] = factory

    def register_singleton(self, service_type: Type[T], factory: callable) -> None:
        """Register a singleton factory."""
        key = service_type.__name__
        self._factories[key] = factory
        self._singletons[key] = None

    def get(self, service_type: Type[T]) -> T:
        """Get a service instance."""
        key = service_type.__name__

        if key in self._singletons:
            if self._singletons[key] is None:
                self._singletons[key] = self._factories[key]()
            return self._singletons[key]

        if key in self._services:
            return self._services[key]

        if key in self._factories:
            return self._factories[key]()

        raise ValueError(f"Service {key} not registered")

    def has(self, service_type: Type[T]) -> bool:
        """Check if a service is registered."""
        key = service_type.__name__
        return key in self._services or key in self._factories


class FileSystem:
    """File system abstraction for dependency injection."""

    def __init__(self, base_path: Path | None = None):
        self.base_path = base_path or Path.cwd()

    def read_text(self, path: str | Path) -> str:
        """Read text from file."""
        full_path = self.base_path / path
        return full_path.read_text(encoding="utf-8")

    def write_text(self, path: str | Path, content: str) -> None:
        """Write text to file."""
        full_path = self.base_path / path
        full_path.parent.mkdir(parents=True, exist_ok=True)
        full_path.write_text(content, encoding="utf-8")

    def exists(self, path: str | Path) -> bool:
        """Check if file exists."""
        full_path = self.base_path / path
        return full_path.exists()

    def glob(self, pattern: str) -> list[Path]:
        """Glob files relative to base path."""
        return list(self.base_path.glob(pattern))

    def mkdir(
        self, path: str | Path, parents: bool = False, exist_ok: bool = False
    ) -> None:
        """Create directory."""
        full_path = self.base_path / path
        full_path.mkdir(parents=parents, exist_ok=exist_ok)


class ProjectManager:
    """Project management operations."""

    def __init__(self, file_system: FileSystem):
        self.file_system = file_system

    def is_anvil_project(self, path: Path) -> bool:
        """Check if directory is an Anvil project."""
        return (
            self.file_system.exists(path / "app.json")
            or self.file_system.exists(path / "client_code")
            or self.file_system.exists(path / "server_code")
        )

    def get_project_files(self, path: Path, pattern: str = "**/*") -> list[Path]:
        """Get all files in project matching pattern."""
        original_base = self.file_system.base_path
        self.file_system.base_path = path
        try:
            return self.file_system.glob(pattern)
        finally:
            self.file_system.base_path = original_base
