"""
FlagResolver - централизованный резолв флагов

Объединяет логику резолва флагов из ContextFactory и FlagService.
Отвечает за разрешение флагов из разных источников:
- Глобальные флаги
- Локальные флаги сцены
- Переменные как флаги
- Conditional flags (rule engine)
"""

import logging
from typing import TYPE_CHECKING, Any

from aiogram.types import CallbackQuery, Message

if TYPE_CHECKING:
    from ui_router.state.context import ExecutionContext
    from ui_router.registry import MasterRegistry
    from .engine import RuleEngine
    from ui_router.schema import Scene, UIRouter, Flag
    from ui_router.state.variables import VariableRepository

logger = logging.getLogger(__name__)


class FlagResolver:
    """
    Централизованный резолв флагов

    Заменяет FlagService и методы резолва флагов из ContextFactory.
    Предоставляет единый интерфейс для резолва всех типов флагов.
    """

    def __init__(
        self,
        schema: "UIRouter",
        registry: "MasterRegistry",
        rule_engine: "RuleEngine",
        variable_repository: "VariableRepository",
    ) -> None:
        """
        Инициализировать FlagResolver

        Args:
            schema: UIRouter схема
            registry: MasterRegistry для кастомных функций
            rule_engine: RuleEngine для conditional flags
            variable_repository: VariableRepository для переменных
        """
        self.schema = schema
        self.registry = registry
        self.rule_engine = rule_engine
        self.variable_repository = variable_repository

    async def resolve_scene_flags(
        self,
        scene: "Scene",
        context: "ExecutionContext",
        event: Message | CallbackQuery | None = None,
    ) -> None:
        """
        Разрешить все флаги для сцены и записать в контекст

        Порядок резолва (каждый следующий может переопределить предыдущий):
        1. Глобальные флаги
        2. Локальные флаги сцены
        3. Переменные как флаги
        4. Conditional flags (rule engine)

        Args:
            scene: Сцена для которой резолвятся флаги
            context: Контекст выполнения
            event: Событие (Message или CallbackQuery)
        """
        context.event_data["ui_router_schema"] = self.schema

        for flag in self.schema.global_flags:
            value = await self.get_flag_value(flag, context, event)
            context.set_flag(flag.name, value)

        for flag in scene.flags:
            value = await self.get_flag_value(flag, context, event)
            context.set_flag(flag.name, value)

        await self.resolve_variables_as_flags(context)

        for cond_flag in self.schema.conditional_flags:
            value = await self.rule_engine.evaluate_conditional_flag(cond_flag, context)
            context.set_flag(cond_flag.name, value)

    async def get_flag_value(
        self,
        flag: "Flag",
        context: "ExecutionContext",
        event: Message | CallbackQuery | None = None,
    ) -> Any:
        """
        Получить значение флага

        Поддерживает разные типы геттеров:
        - static: статическое значение
        - function: вызов функции из registry
        - context: значение из context.event_data
        - user_input: значение из сохранённого ввода пользователя

        Args:
            flag: Флаг для резолва
            context: Контекст выполнения
            event: Событие (для function getters)

        Returns:
            Значение флага или default если не удалось получить
        """
        getter = flag.getter

        if getter.type == "static":
            return getter.value

        if getter.type == "function":
            return await self.registry.getters.get_value(getter.function, context)

        if getter.type == "context":
            return context.get_user_input(getter.context_key, flag.default)

        if getter.type == "user_input":
            return context.get_user_input(getter.input_key, flag.default)

        return flag.default

    async def get_variable_for_condition(self, var_name: str, context: "ExecutionContext") -> Any:
        """
        Получить значение переменной для проверки условия.

        Порядок поиска:
        1. Флаги контекста (уже зарезолвлены)
        2. VariableRepository (пробует все scope: USER, CHAT, BOT)

        Args:
            var_name: Имя переменной
            context: Контекст выполнения

        Returns:
            Значение переменной или None
        """
        value = context.get_flag(var_name)
        if value is not None:
            return value

        bot_id = context.bot.id if context.bot else context.event_data.get("bot_id")

        for scope_name in ["user", "chat", "bot"]:
            try:
                result = await self.variable_repository.get(
                    bot_id=bot_id,
                    name=var_name,
                    scope=scope_name,
                    user_id=context.user_id if scope_name == "user" else None,
                    chat_id=context.chat_id if scope_name == "chat" else None,
                )
                if result is not None:
                    return result
            except Exception:
                continue

        return None

    async def resolve_variables_as_flags(self, context: "ExecutionContext") -> None:
        """
        Резолвить переменные как флаги (чтобы были доступны в темплейтах)

        Для каждой переменной из schema.variables:
        1. Получает значение из VariableRepository
        2. Если значение None - использует default
        3. Добавляет как флаг в контекст

        Args:
            context: Контекст выполнения
        """
        for var in self.schema.variables:
            value = await self.variable_repository.get(
                bot_id=context.bot.id,
                name=var.name,
                scope=var.scope,
                user_id=context.user_id,
                chat_id=context.chat_id,
            )

            if value is None:
                value = var.default

            context.set_flag(var.name, value)

    async def resolve_condition_value(self, value: Any, context: "ExecutionContext") -> Any:
        """
        Разрешить значение условия (может быть ссылка на переменную)

        Если значение - строка вида "{var_name}", то резолвит переменную из:
        1. Флагов контекста
        2. Переменных (пробует все scope: USER, CHAT, BOT)

        Args:
            value: Значение для резолва
            context: Контекст выполнения

        Returns:
            Разрешенное значение или исходное значение если не ссылка
        """
        from ui_router.state.variables import VariableScope

        if isinstance(value, str) and value.startswith("{") and value.endswith("}"):
            var_name = value[1:-1]

            flag_value = context.get_flag(var_name)
            if flag_value is not None:
                return flag_value

            var_value = await self.variable_repository.get(
                bot_id=context.bot.id,
                name=var_name,
                scope=VariableScope.USER,
                user_id=context.user_id,
            )
            if var_value is not None:
                return var_value

            var_value = await self.variable_repository.get(
                bot_id=context.bot.id,
                name=var_name,
                scope=VariableScope.CHAT,
                chat_id=context.chat_id,
            )
            if var_value is not None:
                return var_value

            return await self.variable_repository.get(
                bot_id=context.bot.id,
                name=var_name,
                scope=VariableScope.BOT,
            )

        return value
