"""Domain setup — initialize CQRS buses with handlers.

This module provides a lazy singleton for the command/query buses,
ensuring they are initialized once and shared across CLI and API layers.
"""

from __future__ import annotations

import structlog

from proxym.domain.bus import CommandBus, QueryBus
from proxym.domain.events import EventStore
from proxym.domain.commands.project_commands import (
    AddProjectCommand,
    UpdateProjectCommand,
    RemoveProjectCommand,
    ScanDirectoryCommand,
)
from proxym.domain.commands.setup_commands import (
    ResetSetupChecklistCommand,
    ToggleSetupStepCommand,
)
from proxym.domain.commands.task_commands import (
    CreateTaskCommand,
    AssignTaskCommand,
    CompleteTaskCommand,
)
from proxym.domain.commands.user_commands import (
    CreateUserCommand,
    UpdateUserCommand,
    DeleteUserCommand,
    SyncGitUsersCommand,
)
from proxym.domain.queries.project_queries import (
    ListProjectsQuery,
    GetProjectQuery,
    GetProjectTicketsQuery,
)
from proxym.domain.queries.setup_queries import GetSetupChecklistQuery
from proxym.domain.queries.user_queries import (
    ListUsersQuery,
    GetUserQuery,
    GetDefaultUserQuery,
    GetGitSyncStatusQuery,
)
from proxym.domain.handlers.project_handler import (
    ProjectCommandHandler,
    ProjectQueryHandler,
)
from proxym.domain.handlers.setup_handler import (
    SetupCommandHandler,
    SetupQueryHandler,
    get_setup_projection,
    reset_setup_projection,
)
from proxym.domain.handlers.task_handler import TaskCommandHandler
from proxym.domain.handlers.user_handler import (
    UserCommandHandler,
    UserQueryHandler,
)

logger = structlog.get_logger()

# --- Singletons ---

_command_bus: CommandBus | None = None
_query_bus: QueryBus | None = None
_event_store: EventStore | None = None


def get_event_store() -> EventStore:
    """Get or create the global event store."""
    global _event_store
    if _event_store is None:
        from proxym.storage import DEFAULT_SQLITE_PATH
        _event_store = EventStore(persist_path=DEFAULT_SQLITE_PATH)
    return _event_store


def get_command_bus() -> CommandBus:
    """Get or create the global command bus with registered handlers."""
    global _command_bus
    if _command_bus is None:
        store = get_event_store()
        _command_bus = CommandBus(event_store=store)

        # Get project registry (same lazy singleton pattern)
        from proxym.dashboard._projects_api import _get_registry
        registry = _get_registry()

        # Register project command handler
        handler = ProjectCommandHandler(registry, store)
        _command_bus.register(AddProjectCommand, handler)
        _command_bus.register(UpdateProjectCommand, handler)
        _command_bus.register(RemoveProjectCommand, handler)
        _command_bus.register(ScanDirectoryCommand, handler)

        # Register task command handler
        from proxym.dashboard._tickets_api import _tickets
        task_handler = TaskCommandHandler(_tickets(), store)
        _command_bus.register(CreateTaskCommand, task_handler)
        _command_bus.register(AssignTaskCommand, task_handler)
        _command_bus.register(CompleteTaskCommand, task_handler)

        setup_projection = get_setup_projection(store)
        setup_handler = SetupCommandHandler(setup_projection)
        _command_bus.register(ToggleSetupStepCommand, setup_handler)
        _command_bus.register(ResetSetupChecklistCommand, setup_handler)

        # Register user command handler
        from proxym.dashboard._users_api import _users
        user_mgr = _users()
        user_handler = UserCommandHandler(user_mgr, store)
        _command_bus.register(CreateUserCommand, user_handler)
        _command_bus.register(UpdateUserCommand, user_handler)
        _command_bus.register(DeleteUserCommand, user_handler)
        _command_bus.register(SyncGitUsersCommand, user_handler)

        logger.info("command_bus_initialized", commands=_command_bus.registered_commands)

    return _command_bus


def get_query_bus() -> QueryBus:
    """Get or create the global query bus with registered handlers."""
    global _query_bus
    if _query_bus is None:
        _query_bus = QueryBus()

        from proxym.dashboard._projects_api import _get_registry
        registry = _get_registry()

        handler = ProjectQueryHandler(registry)
        _query_bus.register(ListProjectsQuery, handler)
        _query_bus.register(GetProjectQuery, handler)
        _query_bus.register(GetProjectTicketsQuery, handler)

        setup_projection = get_setup_projection(get_event_store())
        _query_bus.register(GetSetupChecklistQuery, SetupQueryHandler(setup_projection))

        # Register user query handler
        from proxym.dashboard._users_api import _users
        user_mgr = _users()
        user_query_handler = UserQueryHandler(user_mgr)
        _query_bus.register(ListUsersQuery, user_query_handler)
        _query_bus.register(GetUserQuery, user_query_handler)
        _query_bus.register(GetDefaultUserQuery, user_query_handler)
        _query_bus.register(GetGitSyncStatusQuery, user_query_handler)

        logger.info("query_bus_initialized", queries=_query_bus.registered_queries)

    return _query_bus


def reset_buses() -> None:
    """Reset buses (for testing)."""
    global _command_bus, _query_bus, _event_store
    _command_bus = None
    _query_bus = None
    _event_store = None

    reset_setup_projection()
