"""
Основной класс UI роутера - оркестратор всех сервисов
"""

import logging
import asyncio
from collections.abc import Awaitable, Callable
from aiogram import Router
from aiogram.types import Message
from .execution.callbacks import CallbackDataManager
from .events.bus import EventData
from .schema import UIRouter, VariableScope
from .state.context import ExecutionContext, NavigationManager
from .state.factory import ContextFactory
from .rules.flags import FlagResolver
from .registry import MasterRegistry
from .execution.actions import ActionExecutor, ContentResolver
from .events.dispatcher import EventDispatcher
from .events.sync import EventSynchronizer
from .rules.engine import RuleEngine
from .services import (
    SharedServices,
    NavigationService,
    ContentService,
    LocalizationService,
)
from .services.scene_renderer import SceneRenderer
from .aiogram.adapter import AiogramAdapter


logger = logging.getLogger(__name__)


class UIRouterExecutor:
    """Исполнитель UI роутера - оркестратор всех сервисов"""

    def __init__(
        self,
        schema: UIRouter,
        shared: SharedServices,
        enable_fluent: bool | None = None,
        outer_registry: MasterRegistry | None = None,
        prefix: str | None = None,
        event_filter: Callable[[EventData], Awaitable[bool]] | None = None,
    ) -> None:
        """
        Инициализировать UIRouterExecutor.

        Args:
            schema: UIRouter схема с конфигурацией
            shared: SharedServices с общими компонентами (NavigationStorage, VariableRepository, EventBus и т.д.)
            enable_fluent: Включить Fluent для локализации (переопределяет schema.enable_fluent)
            outer_registry: Внешний MasterRegistry (опционально)
            prefix: Префикс для хранилища навигации (для изоляции multiple routers)
            event_filter: Optional async filter for event processing (used for A/B test isolation)
        """
        self.schema = schema
        self.shared = shared
        self.prefix = prefix

        if enable_fluent is not None:
            schema.enable_fluent = enable_fluent

        self.enable_fluent = schema.enable_fluent

        self._initialize_variables()

        self.registry = outer_registry or MasterRegistry()

        self.rule_engine = RuleEngine(variable_repository=shared.variable_repository)

        self.localization_service = LocalizationService(
            schema=schema,
            enable_fluent=self.enable_fluent,
        )

        self.callback_manager = CallbackDataManager(
            strategy=schema.callback_strategy,
            cache_storage=shared.cache_storage,
        )

        navigation_manager = NavigationManager(
            navigation_storage=shared.navigation_storage,
            max_history_depth=schema.navigation.max_history_depth,
            prefix=prefix,
        )

        flag_resolver = FlagResolver(
            schema=schema,
            registry=self.registry,
            rule_engine=self.rule_engine,
            variable_repository=shared.variable_repository,
        )

        self.context_factory = ContextFactory(
            flag_resolver=flag_resolver,
            navigation_manager=navigation_manager,
            schema=schema,
        )

        content_resolver = ContentResolver(
            callback_manager=self.callback_manager,
            fluent_bundles=self.localization_service.fluent_bundles,
        )

        self.content_service = ContentService(
            content_resolver=content_resolver,
        )

        self.action_executor = ActionExecutor(
            content_resolver=content_resolver,
            registry=self.registry,
            event_bus=shared.event_bus,
            event_scheduler=shared.event_scheduler,
            variable_repository=shared.variable_repository,
        )

        self.scene_renderer = SceneRenderer(
            flag_resolver=flag_resolver,
            content_service=self.content_service,
            action_executor=self.action_executor,
            schema=schema,
            analytics_collector=shared.analytics_collector,
        )

        self.navigation_service = NavigationService(
            navigation_manager=navigation_manager,
        )

        throttle_checker = None
        if shared.cache_storage:
            from ui_router.execution.throttle import ThrottleChecker

            throttle_checker = ThrottleChecker(shared.cache_storage)

        from ui_router.services.handler_service import HandlerService

        self.handler_service = HandlerService(
            action_executor=self.action_executor,
            navigation_service=self.navigation_service,
            scene_renderer=self.scene_renderer,
            flag_resolver=flag_resolver,
            schema=schema,
            analytics_collector=shared.analytics_collector,
            throttle_checker=throttle_checker,
        )

        self.event_dispatcher = EventDispatcher(
            schema=schema,
            navigation_manager=navigation_manager,
            action_executor=self.action_executor,
            flag_resolver=flag_resolver,
            variable_repository=shared.variable_repository,
            rule_engine=self.rule_engine,
            context_factory=self.context_factory,
            bot_resolver=shared.bot_resolver,
        )

        self.event_sync = EventSynchronizer(
            event_bus=shared.event_bus,
            event_scheduler=shared.event_scheduler,
            bot_id=getattr(schema, "name", ""),
            event_filter=event_filter,
        )
        try:
            loop = asyncio.get_running_loop()
            self._init_event_sync_task = loop.create_task(self._init_event_sync())
        except RuntimeError:
            self._init_event_sync_task = None

        if schema.custom_functions or schema.business_actions:
            self.registry.load_from_schema(
                schema.custom_functions,
                schema.business_actions,
            )

        self.aiogram_adapter = AiogramAdapter(
            schema=schema,
            callback_manager=self.callback_manager,
            navigation_manager=navigation_manager,
            handler_service=self.handler_service,
            registry=self.registry,
            scene_renderer=self.scene_renderer,
        )

    async def start(self, user_id: int, message: Message = None, **kwargs) -> None:
        """Запустить UI для пользователя"""

        chat_id = kwargs.get("chat_id", user_id)
        bot = kwargs["bot"]

        await self.navigation_service.initialize(bot.id, user_id, chat_id, self.schema.initial_scene)

        nav_state = await self.navigation_service.get_current_state(bot.id, user_id, chat_id)

        if "user_id" not in kwargs:
            kwargs["user_id"] = user_id
        if "chat_id" not in kwargs:
            kwargs["chat_id"] = chat_id

        context = ExecutionContext(
            navigation_manager=self.navigation_service.navigation_manager,
            navigation_state=nav_state,
            bot=bot,
            scene_id=self.schema.initial_scene,
            user_id=user_id,
            chat_id=chat_id,
            event_data={k: v for k, v in kwargs.items() if k != "handler"},
        )

        await self.scene_renderer.enter_scene(self.schema.initial_scene, context, message=message)

    def get_router(self) -> Router:
        """Получить aiogram Router"""
        return self.aiogram_adapter.router

    def _initialize_variables(self) -> None:
        """Инициализировать переменные из схемы с default значениями"""

        async def init() -> None:
            for var in self.schema.variables:
                if var.default is not None and var.scope == VariableScope.BOT:
                    bot_id = self.schema.name
                    existing = await self.shared.variable_repository.get(
                        bot_id=bot_id,
                        name=var.name,
                        scope=var.scope,
                    )

                    if existing is None:
                        await self.shared.variable_repository.set(
                            bot_id=bot_id,
                            name=var.name,
                            value=var.default,
                            scope=var.scope,
                        )

        try:
            loop = asyncio.get_running_loop()
            self._init_variables_task = loop.create_task(init())
        except RuntimeError:
            self._init_variables_task = None

    async def _init_event_sync(self) -> None:
        """Initialize event subscriptions and scheduled tasks."""
        await self.event_sync.subscribe_handlers(self.schema, self.event_dispatcher)
        await self.event_sync.schedule_definitions(self.schema)

    async def reload_schema(self, new_schema: UIRouter, bot_id: int | str | None = None) -> None:
        """
        Перезагрузить UI схему.

        Очищает все зарегистрированные handlers и регистрирует заново
        из новой схемы. Используется для hot reload после изменения
        схемы UI без перезапуска бота.

        Args:
            new_schema: Новая схема UIRouter
            bot_id: ID бота (опционально, для мультибот системы)

        Example:
            # После обновления схемы в БД
            new_schema = await schema_repository.get_schema(bot_id)
            await ui_router.reload_schema(new_schema, bot_id=bot_id)
        """
        logger.info("Reloading schema...")

        old_schema = self.schema

        self.schema = new_schema

        self.localization_service = LocalizationService(
            schema=new_schema,
            enable_fluent=self.enable_fluent,
        )

        self.rule_engine = RuleEngine(variable_repository=self.shared.variable_repository)

        flag_resolver = FlagResolver(
            schema=new_schema,
            registry=self.registry,
            rule_engine=self.rule_engine,
            variable_repository=self.shared.variable_repository,
        )

        navigation_manager = self.navigation_service.navigation_manager

        self.context_factory = ContextFactory(
            flag_resolver=flag_resolver,
            navigation_manager=navigation_manager,
            schema=new_schema,
        )

        content_resolver = ContentResolver(
            callback_manager=self.callback_manager,
            fluent_bundles=self.localization_service.fluent_bundles,
        )

        self.content_service = ContentService(
            content_resolver=content_resolver,
        )

        self.action_executor = ActionExecutor(
            content_resolver=content_resolver,
            registry=self.registry,
            event_bus=self.shared.event_bus,
            event_scheduler=self.shared.event_scheduler,
            variable_repository=self.shared.variable_repository,
        )

        self.scene_renderer = SceneRenderer(
            flag_resolver=flag_resolver,
            content_service=self.content_service,
            action_executor=self.action_executor,
            schema=new_schema,
            analytics_collector=self.shared.analytics_collector,
        )

        if new_schema.custom_functions or new_schema.business_actions:
            self.registry.getters._functions.clear()
            self.registry.conditions._functions.clear()
            self.registry.actions._functions.clear()
            self.registry.business_actions._functions.clear()

            self.registry.load_from_schema(
                new_schema.custom_functions,
                new_schema.business_actions,
            )

        self._initialize_variables()

        throttle_checker = None
        if self.shared.cache_storage:
            from ui_router.execution.throttle import ThrottleChecker

            throttle_checker = ThrottleChecker(self.shared.cache_storage)

        from ui_router.services.handler_service import HandlerService

        self.handler_service = HandlerService(
            action_executor=self.action_executor,
            navigation_service=self.navigation_service,
            scene_renderer=self.scene_renderer,
            flag_resolver=flag_resolver,
            schema=new_schema,
            analytics_collector=self.shared.analytics_collector,
            throttle_checker=throttle_checker,
        )

        self.event_dispatcher = EventDispatcher(
            schema=new_schema,
            navigation_manager=navigation_manager,
            action_executor=self.action_executor,
            flag_resolver=flag_resolver,
            variable_repository=self.shared.variable_repository,
            rule_engine=self.rule_engine,
            context_factory=self.context_factory,
            bot_resolver=self.shared.bot_resolver,
        )

        await self.event_sync.sync(old_schema, new_schema, self.event_dispatcher)

        self.aiogram_adapter.reload(
            schema=new_schema,
            handler_service=self.handler_service,
            scene_renderer=self.scene_renderer,
            registry=self.registry,
        )

        logger.info("Schema reloaded successfully")
        logger.debug(
            "  - Scenes: %s, Global handlers: %s, Variables: %s, Conditional flags: %s",
            len(new_schema.scenes),
            len(new_schema.global_handlers),
            len(new_schema.variables),
            len(new_schema.conditional_flags),
        )
