"""CLI application bootstrap and dependency injection setup."""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from portal.core.events.event_bus import EventBus
from portal.shared.container import ServiceContainer

if TYPE_CHECKING:
    from collections.abc import Callable


def bootstrap_services() -> ServiceContainer:
    """Bootstrap CLI application with all dependencies."""
    from portal.core.services.color_service import ColorService
    from portal.core.services.color_theme_service import ColorThemeService
    from portal.core.services.config_service import ConfigService
    from portal.core.services.hook_config_service import HookConfigService
    from portal.core.services.hook_service import HookService
    from portal.core.services.hook_service_adapter import HookServiceAdapter
    from portal.core.services.integration_service import IntegrationService
    from portal.core.services.worktree_service import WorktreeService
    from portal.infrastructure.ai.claude_context import ClaudeContextProvider
    from portal.infrastructure.config.yaml_config_repository import YamlConfigRepository
    from portal.infrastructure.editors.cursor_adapter import CursorAdapter
    from portal.infrastructure.editors.vscode_adapter import VSCodeAdapter
    from portal.infrastructure.filesystem.filesystem_operations import FileSystemOperations
    from portal.infrastructure.git.git_repository import GitRepository
    from portal.infrastructure.integrations.event_handlers import IntegrationEventHandler
    from portal.infrastructure.shell.shell_executor import ShellExecutor
    from portal.infrastructure.template.template_engine import TemplateEngine
    from portal.infrastructure.terminals.iterm_adapter import ITermAdapter
    from portal.infrastructure.terminals.terminal_adapter import TerminalAdapter
    from portal.interfaces.cli.controllers.config_controller import ConfigController
    from portal.interfaces.cli.controllers.hook_controller import HookController
    from portal.interfaces.cli.controllers.integration_controller import IntegrationController
    from portal.interfaces.cli.controllers.shell_controller import ShellController
    from portal.interfaces.cli.controllers.worktree_controller import WorktreeController
    from portal.interfaces.cli.presenters.integration_presenter import IntegrationPresenter
    from portal.interfaces.cli.presenters.menu_presenter import MenuPresenter
    from portal.interfaces.cli.presenters.output_presenter import OutputPresenter

    container = ServiceContainer()

    # Register core infrastructure as singletons
    container.register_singleton(EventBus, lambda _: EventBus())

    def create_git_repository(_: ServiceContainer) -> GitRepository:
        import git

        # Find the actual Git repository root, searching parent directories if needed
        try:
            repo = git.Repo(Path.cwd(), search_parent_directories=True)
            repo_root = Path(repo.working_dir)
            return GitRepository(repo_root)
        except git.InvalidGitRepositoryError:
            # Fall back to current directory if no Git repo found
            return GitRepository(Path.cwd())

    container.register_factory(GitRepository, create_git_repository)

    container.register_singleton(YamlConfigRepository, lambda _: YamlConfigRepository())
    container.register_singleton(FileSystemOperations, lambda _: FileSystemOperations())
    container.register_singleton(ShellExecutor, lambda _: ShellExecutor())
    container.register_singleton(TemplateEngine, lambda _: TemplateEngine())

    # Register external integration adapters as singletons
    container.register_singleton(ITermAdapter, lambda _: ITermAdapter())
    container.register_singleton(TerminalAdapter, lambda _: TerminalAdapter())

    def create_cursor_adapter(c: ServiceContainer) -> CursorAdapter:
        return CursorAdapter(c.resolve(ColorThemeService))

    def create_vscode_adapter(c: ServiceContainer) -> VSCodeAdapter:
        return VSCodeAdapter(c.resolve(ColorThemeService))

    container.register_singleton(CursorAdapter, create_cursor_adapter)
    container.register_singleton(VSCodeAdapter, create_vscode_adapter)
    container.register_singleton(ClaudeContextProvider, lambda _: ClaudeContextProvider())

    # Register core services as singletons
    container.register_singleton(ColorService, lambda _: ColorService())
    container.register_singleton(ColorThemeService, lambda _: ColorThemeService())

    def create_config_service(c: ServiceContainer) -> ConfigService:
        return ConfigService(c.resolve(YamlConfigRepository))

    container.register_singleton(ConfigService, create_config_service)

    def create_hook_service(c: ServiceContainer) -> HookService:
        return HookService(
            c.resolve(ShellExecutor),
            c.resolve(FileSystemOperations),
            c.resolve(TemplateEngine),
            c.resolve(EventBus),
        )

    container.register_singleton(HookService, create_hook_service)

    # Register HookConfigService
    def create_hook_config_service(c: ServiceContainer) -> HookConfigService:
        return HookConfigService(c.resolve(ConfigService))

    container.register_singleton(HookConfigService, create_hook_config_service)

    # Create HookServiceAdapter
    def create_hook_service_adapter(c: ServiceContainer) -> HookServiceAdapter:
        from portal.core.domain.models.config import PortalConfig

        default_config = PortalConfig(
            version="1.0", base_dir="../{project}_worktrees", default_base_branch="main"
        )

        return HookServiceAdapter(
            hook_service=c.resolve(HookService),
            hook_config_service=c.resolve(HookConfigService),
            config=default_config,
        )

    container.register_singleton(HookServiceAdapter, create_hook_service_adapter)

    def create_worktree_service(c: ServiceContainer) -> WorktreeService:
        # Load the actual configuration including project-specific settings
        config_service = c.resolve(ConfigService)
        git_repo = c.resolve(GitRepository)

        # Load config with project path to get project-specific overrides
        import asyncio

        config = asyncio.run(config_service.get_config(git_repo.repo_path))

        return WorktreeService(
            git_repository=git_repo,
            hook_service=c.resolve(HookServiceAdapter),
            color_service=c.resolve(ColorService),
            event_bus=c.resolve(EventBus),
            config=config,
            config_service=config_service,
        )

    container.register_singleton(WorktreeService, create_worktree_service)

    def create_integration_service(c: ServiceContainer) -> IntegrationService:
        return IntegrationService(
            iterm_adapter=c.resolve(ITermAdapter),
            terminal_adapter=c.resolve(TerminalAdapter),
            cursor_adapter=c.resolve(CursorAdapter),
            vscode_adapter=c.resolve(VSCodeAdapter),
        )

    container.register_singleton(IntegrationService, create_integration_service)

    def create_integration_event_handler(c: ServiceContainer) -> IntegrationEventHandler:
        return IntegrationEventHandler(
            event_bus=c.resolve(EventBus),
            config_service=c.resolve(ConfigService),
            iterm_adapter=c.resolve(ITermAdapter),
            terminal_adapter=c.resolve(TerminalAdapter),
            cursor_adapter=c.resolve(CursorAdapter),
            vscode_adapter=c.resolve(VSCodeAdapter),
            claude_context=c.resolve(ClaudeContextProvider),
        )

    container.register_singleton(IntegrationEventHandler, create_integration_event_handler)

    # Eagerly load IntegrationEventHandler to ensure event subscriptions are registered
    # This ensures color syncing with editors works when worktrees are created
    container.resolve(IntegrationEventHandler)

    # Register presenters as singletons
    def create_menu_presenter(c: ServiceContainer) -> MenuPresenter:
        return MenuPresenter(c.resolve(ColorService))

    container.register_singleton(MenuPresenter, create_menu_presenter)
    container.register_singleton(OutputPresenter, lambda _: OutputPresenter())
    container.register_singleton(IntegrationPresenter, lambda _: IntegrationPresenter())

    # Register controllers (not singletons - can be created per command)
    def create_worktree_controller(c: ServiceContainer) -> WorktreeController:
        return WorktreeController(
            worktree_service=c.resolve(WorktreeService),
            config_service=c.resolve(ConfigService),
            color_service=c.resolve(ColorService),
            menu_presenter=c.resolve(MenuPresenter),
            output_presenter=c.resolve(OutputPresenter),
            iterm_adapter=c.resolve(ITermAdapter),
            cursor_adapter=c.resolve(CursorAdapter),
        )

    container.register_factory(WorktreeController, create_worktree_controller)

    def create_config_controller(c: ServiceContainer) -> ConfigController:
        return ConfigController(
            config_service=c.resolve(ConfigService), output_presenter=c.resolve(OutputPresenter)
        )

    container.register_factory(ConfigController, create_config_controller)

    def create_hook_controller(c: ServiceContainer) -> HookController:
        return HookController(
            hook_service=c.resolve(HookService), output_presenter=c.resolve(OutputPresenter)
        )

    container.register_factory(HookController, create_hook_controller)

    def create_shell_controller(c: ServiceContainer) -> ShellController:
        return ShellController(output_presenter=c.resolve(OutputPresenter))

    container.register_factory(ShellController, create_shell_controller)

    def create_integration_controller(c: ServiceContainer) -> IntegrationController:
        return IntegrationController(
            integration_service=c.resolve(IntegrationService),
            integration_presenter=c.resolve(IntegrationPresenter),
            output_presenter=c.resolve(OutputPresenter),
        )

    container.register_factory(IntegrationController, create_integration_controller)

    return container


# Global container instance
_container: ServiceContainer | None = None


def get_container() -> ServiceContainer:
    """Get or create the service container."""
    global _container
    if _container is None:
        _container = bootstrap_services()
    return _container


def create_cli_app() -> Callable[[], None]:
    """Create and configure the CLI application."""
    from portal.interfaces.cli.commands import create_portal_cli

    return create_portal_cli(get_container)
