from datetime import datetime, timedelta
from math import ceil
from typing import Any

from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder

from config import USE_NEW_PAYMENT_FLOW
from core.settings.tariffs_config import normalize_tariff_config
from database import get_balance, get_tariff_by_id
from database.notifications import check_hot_lead_discount
from handlers.buttons import CONFIG_PAY_BUTTON_TEXT, MAIN_MENU, PAYMENT
from handlers.payments.currency_rates import format_for_user
from handlers.payments.fast_payment_flow import try_fast_payment_flow
from handlers.tariffs.tariff_display import GB
from handlers.texts import (
    CONFIG_SCREEN_TEMPLATE,
    CREATING_CONNECTION_MSG,
    DEFAULT_LIMIT_LABEL,
    INSUFFICIENT_FUNDS_MSG,
    UNLIMITED_DEVICES_LABEL,
    UNLIMITED_TRAFFIC_LABEL,
)
from handlers.utils import edit_or_send_message
from hooks.processors import process_check_discount_validity
from logger import logger


router = Router()


CREATING_KEY_BUTTON_TEXT = "⏳ Подождите..."


class TariffUserConfigState(StatesGroup):
    """Состояния конфигуратора тарифа для пользователя."""

    configuring = State()


def calculate_config_price(
    tariff: dict,
    selected_device_limit: int | None = None,
    selected_traffic_gb: int | None = None,
) -> int:
    """Рассчитывает цену тарифа с учётом выбранных лимитов."""
    cfg = normalize_tariff_config(tariff)

    base_price = int(tariff.get("price_rub") or 0)

    raw_device_options = tariff.get("device_options")
    raw_traffic_options = tariff.get("traffic_options_gb")

    raw_device_options = raw_device_options if isinstance(raw_device_options, list) else []
    raw_traffic_options = raw_traffic_options if isinstance(raw_traffic_options, list) else []

    device_values: list[int] = []
    for value in raw_device_options:
        try:
            device_values.append(int(value))
        except (TypeError, ValueError):
            continue

    traffic_values: list[int] = []
    for value in raw_traffic_options:
        try:
            traffic_values.append(int(value))
        except (TypeError, ValueError):
            continue

    positive_device_values = [v for v in device_values if v > 0]
    positive_traffic_values = [v for v in traffic_values if v > 0]

    base_device_limit = cfg.get("base_device_limit")
    if base_device_limit is None:
        base_device_limit = tariff.get("device_limit")
    if base_device_limit is None:
        if positive_device_values:
            base_device_limit = min(positive_device_values)
        elif device_values:
            base_device_limit = device_values[0]
    base_device_limit = int(base_device_limit) if base_device_limit is not None else None

    base_traffic_gb = cfg.get("base_traffic_gb")
    if base_traffic_gb is None:
        traffic_limit_raw = tariff.get("traffic_limit")
        if traffic_limit_raw:
            traffic_limit_raw = int(traffic_limit_raw)
            if traffic_limit_raw >= GB:
                base_traffic_gb = int(traffic_limit_raw / GB)
            else:
                base_traffic_gb = traffic_limit_raw
        else:
            if positive_traffic_values:
                base_traffic_gb = min(positive_traffic_values)
            elif traffic_values:
                base_traffic_gb = traffic_values[0]
    base_traffic_gb = int(base_traffic_gb) if base_traffic_gb is not None else None

    device_overrides = cfg.get("device_price_overrides") or tariff.get("device_overrides") or {}
    traffic_overrides = cfg.get("traffic_price_overrides") or tariff.get("traffic_overrides") or {}

    extra_device_step_price = int(cfg.get("extra_device_base_price_rub") or tariff.get("device_step_rub") or 0)
    extra_traffic_step_price = int(
        cfg.get("extra_traffic_base_price_per_gb_rub") or tariff.get("traffic_step_rub") or 0
    )

    devices_extra_price = 0
    traffic_extra_price = 0

    if selected_device_limit is not None and base_device_limit is not None:
        selected_device_limit = int(selected_device_limit)
        override_key = str(selected_device_limit)

        if override_key in device_overrides:
            devices_extra_price = int(device_overrides[override_key])
        else:
            if selected_device_limit <= 0:
                if positive_device_values:
                    effective_devices = max(positive_device_values)
                    extra_devices = max(0, effective_devices - base_device_limit)
                    devices_extra_price = extra_devices * extra_device_step_price
            else:
                extra_devices = max(0, selected_device_limit - base_device_limit)
                devices_extra_price = extra_devices * extra_device_step_price

    if selected_traffic_gb is not None and base_traffic_gb is not None:
        selected_traffic_gb = int(selected_traffic_gb)
        override_key = str(selected_traffic_gb)

        if override_key in traffic_overrides:
            traffic_extra_price = int(traffic_overrides[override_key])
        else:
            if selected_traffic_gb <= 0:
                if positive_traffic_values:
                    effective_gb = max(positive_traffic_values)
                    extra_traffic = max(0, effective_gb - base_traffic_gb)
                    traffic_extra_price = extra_traffic * extra_traffic_step_price
            else:
                extra_traffic = max(0, selected_traffic_gb - base_traffic_gb)
                traffic_extra_price = extra_traffic * extra_traffic_step_price

    total_price = int(base_price + devices_extra_price + traffic_extra_price)
    return total_price


async def start_tariff_config(
    callback_query: CallbackQuery,
    state: FSMContext,
    session: Any,
    tariff_id: int,
):
    """Запускает конфигуратор тарифа по id."""
    tariff = await get_tariff_by_id(session, int(tariff_id))
    if not tariff:
        await edit_or_send_message(
            target_message=callback_query.message,
            text="❌ Указанный тариф не найден.",
        )
        await callback_query.answer()
        logger.warning(f"[TARIFF_CFG] start_tariff_config tariff_not_found: tariff_id={tariff_id}")
        return

    if not tariff.get("configurable"):
        await edit_or_send_message(
            target_message=callback_query.message,
            text="❌ Этот тариф нельзя настроить.",
        )
        await callback_query.answer()
        logger.info(f"[TARIFF_CFG] start_tariff_config not_configurable: tariff_id={tariff_id}")
        return

    await start_user_tariff_configurator(
        callback_query=callback_query,
        session=session,
        state=state,
        tariff=tariff,
    )


async def proceed_purchase_with_values(
    callback_query: CallbackQuery,
    session: Any,
    state: FSMContext,
    tariff: dict,
    duration_days: int,
    price_rub: int,
    selected_device_limit: int | None = None,
    selected_traffic_gb: int | None = None,
):
    """Проверяет баланс и создаёт ключ по выбранной конфигурации."""
    from ...keys.key_create import create_key, moscow_tz

    tg_id = callback_query.from_user.id

    logger.info(
        "[TARIFF_CFG] proceed_purchase_with_values: "
        f"tg_id={tg_id} tariff_id={tariff.get('id')} duration_days={duration_days} "
        f"price_rub={price_rub} selected_device_limit={selected_device_limit} "
        f"selected_traffic_gb={selected_traffic_gb}"
    )

    balance = await get_balance(session, tg_id)

    if balance < price_rub:
        required_amount = ceil(price_rub - balance)

        logger.info(
            f"[TARIFF_CFG] insufficient_balance: tg_id={tg_id} balance={balance} required_amount={required_amount}"
        )

        if USE_NEW_PAYMENT_FLOW:
            handled = await try_fast_payment_flow(
                callback_query,
                session,
                state,
                tg_id=tg_id,
                temp_key="waiting_for_payment",
                temp_payload={
                    "tariff_id": tariff["id"],
                    "selected_price_rub": price_rub,
                    "selected_duration_days": duration_days,
                    "selected_device_limit": selected_device_limit,
                    "selected_traffic_limit_gb": selected_traffic_gb,
                    "required_amount": required_amount,
                },
                required_amount=required_amount,
            )
            if handled:
                return

        language_code = getattr(callback_query.from_user, "language_code", None)
        required_amount_text = await format_for_user(session, tg_id, float(required_amount), language_code)

        builder = InlineKeyboardBuilder()
        builder.row(InlineKeyboardButton(text=PAYMENT, callback_data="pay"))
        builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
        await edit_or_send_message(
            target_message=callback_query.message,
            text=INSUFFICIENT_FUNDS_MSG.format(required_amount=required_amount_text),
            reply_markup=builder.as_markup(),
        )
        return

    builder = InlineKeyboardBuilder()
    builder.row(InlineKeyboardButton(text=CREATING_KEY_BUTTON_TEXT, callback_data="creating_key"))
    await edit_or_send_message(
        target_message=callback_query.message,
        text=CREATING_CONNECTION_MSG,
        reply_markup=builder.as_markup(),
    )
    await callback_query.answer()

    expiry_time = datetime.now(moscow_tz) + timedelta(days=duration_days)

    data_to_update: dict[str, Any] = {"tariff_id": tariff["id"], "selected_price_rub": price_rub}
    if selected_device_limit is not None:
        data_to_update["config_selected_device_limit"] = selected_device_limit
    if selected_traffic_gb is not None:
        data_to_update["config_selected_traffic_gb"] = selected_traffic_gb

    await state.update_data(**data_to_update)

    logger.info(f"[TARIFF_CFG] create_key: tg_id={tg_id} tariff_id={tariff.get('id')} expiry_time={expiry_time}")

    await create_key(
        tg_id=tg_id,
        expiry_time=expiry_time,
        state=state,
        session=session,
        message_or_query=callback_query,
        plan=tariff["id"],
        selected_duration_days=duration_days,
        selected_device_limit=selected_device_limit,
        selected_traffic_gb=selected_traffic_gb,
        selected_price_rub=price_rub,
    )


async def render_user_config_screen(
    callback_query: CallbackQuery,
    state: FSMContext,
    session: Any,
):
    """Рендерит экран конфигурации тарифа для пользователя."""
    data = await state.get_data()
    tariff_id = data.get("config_tariff_id")
    cfg = data.get("tariff_config") or {}

    tariff = await get_tariff_by_id(session, int(tariff_id))
    if not tariff:
        await edit_or_send_message(
            target_message=callback_query.message,
            text="❌ Тариф не найден.",
            reply_markup=None,
        )
        await state.clear()
        logger.warning(f"[TARIFF_CFG] render_user_config_screen tariff_not_found: tariff_id={tariff_id}")
        return

    raw_device_options = tariff.get("device_options")
    raw_traffic_options = tariff.get("traffic_options_gb")

    raw_device_options = raw_device_options if isinstance(raw_device_options, list) else []
    raw_traffic_options = raw_traffic_options if isinstance(raw_traffic_options, list) else []

    try:
        device_options = sorted(raw_device_options, key=lambda v: (int(v) == 0, int(v)))
    except (TypeError, ValueError):
        device_options = raw_device_options

    try:
        traffic_options = sorted(raw_traffic_options, key=lambda v: (int(v) == 0, int(v)))
    except (TypeError, ValueError):
        traffic_options = raw_traffic_options

    device_int_options: list[int] = []
    for value in device_options:
        try:
            device_int_options.append(int(value))
        except (TypeError, ValueError):
            continue

    traffic_int_options: list[int] = []
    for value in traffic_options:
        try:
            traffic_int_options.append(int(value))
        except (TypeError, ValueError):
            continue

    has_device_option = bool(device_int_options)
    has_traffic_option = bool(traffic_int_options)
    has_device_choice = len(device_int_options) > 1
    has_traffic_choice = len(traffic_int_options) > 1

    selected_devices = data.get("config_selected_device_limit")
    selected_traffic_gb = data.get("config_selected_traffic_gb")

    base_device_limit = cfg.get("base_device_limit")
    if base_device_limit is None:
        base_device_limit = tariff.get("device_limit")
    if base_device_limit is None:
        positives = [v for v in device_int_options if v > 0]
        if positives:
            base_device_limit = min(positives)
        elif device_int_options:
            base_device_limit = device_int_options[0]
    base_device = int(base_device_limit) if base_device_limit is not None else None

    base_traffic_gb = None
    raw_base_traffic = tariff.get("traffic_limit")
    if raw_base_traffic:
        raw_base_traffic = int(raw_base_traffic)
        if raw_base_traffic >= GB:
            base_traffic_gb = int(raw_base_traffic / GB)
        else:
            base_traffic_gb = raw_base_traffic
    if base_traffic_gb is None:
        cfg_base_traffic = cfg.get("base_traffic_gb")
        if cfg_base_traffic is not None and int(cfg_base_traffic) > 0:
            base_traffic_gb = int(cfg_base_traffic)
    if base_traffic_gb is None:
        positives = [v for v in traffic_int_options if v > 0]
        if positives:
            base_traffic_gb = min(positives)
        elif traffic_int_options:
            base_traffic_gb = traffic_int_options[0]
    base_traffic_gb = int(base_traffic_gb) if base_traffic_gb is not None else None

    if has_device_option:
        if selected_devices is None:
            if base_device is not None and base_device in device_int_options:
                selected_devices = base_device
            elif device_int_options:
                selected_devices = device_int_options[0]
    else:
        selected_devices = None

    if has_traffic_option:
        if selected_traffic_gb is None:
            if base_traffic_gb is not None and base_traffic_gb in traffic_int_options:
                selected_traffic_gb = base_traffic_gb
            elif traffic_int_options:
                selected_traffic_gb = traffic_int_options[0]
    else:
        selected_traffic_gb = None

    final_price = calculate_config_price(
        tariff=tariff,
        selected_device_limit=int(selected_devices) if selected_devices is not None and has_device_option else None,
        selected_traffic_gb=int(selected_traffic_gb)
        if selected_traffic_gb is not None and has_traffic_option
        else None,
    )

    tg_id = callback_query.from_user.id
    language_code = getattr(callback_query.from_user, "language_code", None)
    price_text = await format_for_user(session, tg_id, float(final_price), language_code)

    base_parts = []
    if base_device is not None:
        if int(base_device) <= 0:
            base_devices_label = UNLIMITED_DEVICES_LABEL
        else:
            base_devices_label = f"{int(base_device)} устройств"
        base_parts.append(base_devices_label)

    if base_traffic_gb is not None:
        if int(base_traffic_gb) <= 0:
            base_traffic_label = UNLIMITED_TRAFFIC_LABEL
        else:
            base_traffic_label = f"{int(base_traffic_gb)} ГБ"
        base_parts.append(base_traffic_label)

    if not base_parts:
        base_text = DEFAULT_LIMIT_LABEL
    else:
        base_text = ", ".join(base_parts)

    choice_parts = []

    if has_device_choice:
        if selected_devices is None:
            devices_label = DEFAULT_LIMIT_LABEL
        else:
            if int(selected_devices) <= 0:
                devices_label = UNLIMITED_DEVICES_LABEL
            else:
                devices_label = f"{int(selected_devices)} устройств"
        choice_parts.append(devices_label)

    if has_traffic_choice:
        if selected_traffic_gb is None:
            traffic_label = DEFAULT_LIMIT_LABEL
        else:
            if selected_traffic_gb <= 0:
                traffic_label = UNLIMITED_TRAFFIC_LABEL
            else:
                traffic_label = f"{int(selected_traffic_gb)} ГБ"
        choice_parts.append(traffic_label)

    if not choice_parts:
        choice_text = DEFAULT_LIMIT_LABEL
    else:
        choice_text = ", ".join(choice_parts)

    text = CONFIG_SCREEN_TEMPLATE.format(
        base=base_text,
        choice=choice_text,
        price=price_text,
    )

    builder = InlineKeyboardBuilder()

    device_buttons: list[InlineKeyboardButton] = []
    traffic_buttons: list[InlineKeyboardButton] = []

    if has_device_choice:
        selected_devices_int = int(selected_devices or 0)
        for value in device_int_options:
            mark = " ✅" if value == selected_devices_int else ""
            if value == 0:
                caption = f"{UNLIMITED_DEVICES_LABEL.capitalize()}{mark}"
            else:
                caption = f"{value} устройств{mark}"
            device_buttons.append(
                InlineKeyboardButton(
                    text=caption,
                    callback_data=f"cfg_user_devices|{tariff_id}|{value}",
                )
            )

    if has_traffic_choice:
        selected_traffic_int = int(selected_traffic_gb or 0)
        for value in traffic_int_options:
            mark = " ✅" if value == selected_traffic_int else ""
            if value == 0:
                caption = f"{UNLIMITED_TRAFFIC_LABEL.capitalize()}{mark}"
            else:
                caption = f"{value} ГБ{mark}"
            traffic_buttons.append(
                InlineKeyboardButton(
                    text=caption,
                    callback_data=f"cfg_user_traffic|{tariff_id}|{value}",
                )
            )

    if device_buttons and traffic_buttons:
        max_len = max(len(device_buttons), len(traffic_buttons))
        for i in range(max_len):
            row = []
            if i < len(device_buttons):
                row.append(device_buttons[i])
            if i < len(traffic_buttons):
                row.append(traffic_buttons[i])
            builder.row(*row)
    elif device_buttons:
        for i in range(0, len(device_buttons), 2):
            builder.row(*device_buttons[i : i + 2])
    elif traffic_buttons:
        for i in range(0, len(traffic_buttons), 2):
            builder.row(*traffic_buttons[i : i + 2])

    is_renew_mode = data.get("renew_mode") == "renew"
    confirm_prefix = "cfg_renew_confirm" if is_renew_mode else "cfg_user_confirm"

    builder.row(
        InlineKeyboardButton(
            text=CONFIG_PAY_BUTTON_TEXT.format(amount=price_text),
            callback_data=f"{confirm_prefix}|{tariff_id}",
        )
    )
    builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))

    await state.update_data(
        config_selected_device_limit=selected_devices,
        config_selected_traffic_gb=selected_traffic_gb,
    )

    await edit_or_send_message(
        target_message=callback_query.message,
        text=text,
        reply_markup=builder.as_markup(),
    )
    await callback_query.answer()


async def start_user_tariff_configurator(
    callback_query: CallbackQuery,
    session: Any,
    state: FSMContext,
    tariff: dict,
):
    """Запускает конфигуратор тарифа для пользователя."""
    cfg = normalize_tariff_config(tariff)

    raw_device_options = tariff.get("device_options")
    raw_traffic_options = tariff.get("traffic_options_gb")

    raw_device_options = raw_device_options if isinstance(raw_device_options, list) else []
    raw_traffic_options = raw_traffic_options if isinstance(raw_traffic_options, list) else []

    try:
        device_options = sorted(raw_device_options, key=lambda v: (int(v) == 0, int(v)))
    except (TypeError, ValueError):
        device_options = raw_device_options

    try:
        traffic_options = sorted(raw_traffic_options, key=lambda v: (int(v) == 0, int(v)))
    except (TypeError, ValueError):
        traffic_options = raw_traffic_options

    logger.info(
        "[TARIFF_CFG] start_user_tariff_configurator: "
        f"tg_id={callback_query.from_user.id} tariff_id={tariff.get('id')} "
        f"device_options={device_options} traffic_options={traffic_options}"
    )

    if not device_options and not traffic_options:
        await edit_or_send_message(
            target_message=callback_query.message,
            text="❌ Конфигуратор для этого тарифа не настроен. Попробуйте выбрать другой тариф.",
            reply_markup=None,
        )
        await callback_query.answer()
        logger.warning(f"[TARIFF_CFG] configurator_not_configured: tariff_id={tariff.get('id')}")
        return

    cfg_for_state = dict(cfg)
    cfg_for_state["device_options"] = device_options
    cfg_for_state["traffic_options_gb"] = traffic_options

    data = await state.get_data()
    renew_mode = data.get("renew_mode")

    update_payload: dict[str, Any] = {
        "config_tariff_id": tariff["id"],
        "tariff_config": cfg_for_state,
    }
    if renew_mode != "renew":
        update_payload["config_selected_device_limit"] = None
        update_payload["config_selected_traffic_gb"] = None

    await state.update_data(**update_payload)
    await state.set_state(TariffUserConfigState.configuring)

    await render_user_config_screen(callback_query, state, session)


async def show_price_and_confirm(callback_query: CallbackQuery, state: FSMContext, session: Any | None):
    """Обновляет экран конфигурации и показывает актуальную цену."""
    if session is None:
        from database import async_session_maker

        async with async_session_maker() as new_session:
            await show_price_and_confirm(callback_query, state, new_session)
        return

    await render_user_config_screen(callback_query, state, session)


async def finalize_config_and_purchase(callback_query: CallbackQuery, state: FSMContext, session: Any | None):
    """Фиксирует выбор пользователя и проводит оплату тарифа."""
    data = await state.get_data()
    tariff_id = data.get("config_tariff_id")
    cfg = data.get("tariff_config") or {}

    if session is None:
        from database import async_session_maker

        async with async_session_maker() as new_session:
            await finalize_config_and_purchase(callback_query, state, new_session)
        return

    tariff = await get_tariff_by_id(session, int(tariff_id))
    if not tariff:
        await edit_or_send_message(
            target_message=callback_query.message,
            text="❌ Тариф не найден.",
            reply_markup=None,
        )
        await state.clear()
        logger.warning(f"[TARIFF_CFG] finalize_config_and_purchase tariff_not_found: tariff_id={tariff_id}")
        return

    duration_days = int(tariff.get("duration_days") or 30)

    raw_device_options = tariff.get("device_options")
    raw_traffic_options = tariff.get("traffic_options_gb")

    raw_device_options = raw_device_options if isinstance(raw_device_options, list) else []
    raw_traffic_options = raw_traffic_options if isinstance(raw_traffic_options, list) else []

    try:
        device_options = sorted(raw_device_options, key=lambda v: (int(v) == 0, int(v)))
    except (TypeError, ValueError):
        device_options = raw_device_options

    try:
        traffic_options = sorted(raw_traffic_options, key=lambda v: (int(v) == 0, int(v)))
    except (TypeError, ValueError):
        traffic_options = raw_traffic_options

    device_int_options: list[int] = []
    for value in device_options:
        try:
            device_int_options.append(int(value))
        except (TypeError, ValueError):
            continue

    traffic_int_options: list[int] = []
    for value in traffic_options:
        try:
            traffic_int_options.append(int(value))
        except (TypeError, ValueError):
            continue

    has_device_choice = bool(device_int_options)
    has_traffic_choice = bool(traffic_int_options)

    selected_devices = data.get("config_selected_device_limit")
    selected_traffic_gb = data.get("config_selected_traffic_gb")

    base_device_limit = cfg.get("base_device_limit")
    if base_device_limit is None:
        base_device_limit = tariff.get("device_limit")
    if base_device_limit is None:
        positives = [v for v in device_int_options if v > 0]
        if positives:
            base_device_limit = min(positives)
        elif device_int_options:
            base_device_limit = device_int_options[0]
    base_device = int(base_device_limit) if base_device_limit is not None else None

    base_traffic_gb = None
    raw_base_traffic = tariff.get("traffic_limit")
    if raw_base_traffic:
        raw_base_traffic = int(raw_base_traffic)
        if raw_base_traffic >= GB:
            base_traffic_gb = int(raw_base_traffic / GB)
        else:
            base_traffic_gb = raw_base_traffic
    if base_traffic_gb is None:
        cfg_base_traffic = cfg.get("base_traffic_gb")
        if cfg_base_traffic is not None and int(cfg_base_traffic) > 0:
            base_traffic_gb = int(cfg_base_traffic)
    if base_traffic_gb is None:
        positives = [v for v in traffic_int_options if v > 0]
        if positives:
            base_traffic_gb = min(positives)
        elif traffic_int_options:
            base_traffic_gb = traffic_int_options[0]
    base_traffic_gb = int(base_traffic_gb) if base_traffic_gb is not None else None

    if has_device_choice:
        if selected_devices is None:
            if base_device is not None and base_device in device_int_options:
                selected_devices = base_device
            elif device_int_options:
                selected_devices = device_int_options[0]
    else:
        selected_devices = None

    if has_traffic_choice:
        if selected_traffic_gb is None:
            if base_traffic_gb is not None and base_traffic_gb in traffic_int_options:
                selected_traffic_gb = base_traffic_gb
            elif traffic_int_options:
                selected_traffic_gb = traffic_int_options[0]
    else:
        selected_traffic_gb = None

    final_price = calculate_config_price(
        tariff=tariff,
        selected_device_limit=int(selected_devices) if selected_devices is not None and has_device_choice else None,
        selected_traffic_gb=int(selected_traffic_gb)
        if selected_traffic_gb is not None and has_traffic_choice
        else None,
    )

    logger.info(
        "[TARIFF_CFG] finalize_config_and_purchase: "
        f"tg_id={callback_query.from_user.id} tariff_id={tariff_id} duration_days={duration_days} "
        f"selected_devices={selected_devices} selected_traffic_gb={selected_traffic_gb} "
        f"final_price={final_price}"
    )

    await proceed_purchase_with_values(
        callback_query=callback_query,
        session=session,
        state=state,
        tariff=tariff,
        duration_days=duration_days,
        price_rub=final_price,
        selected_device_limit=int(selected_devices) if selected_devices is not None and has_device_choice else None,
        selected_traffic_gb=int(selected_traffic_gb)
        if selected_traffic_gb is not None and has_traffic_choice
        else None,
    )


@router.callback_query(F.data.startswith("select_tariff_plan|"))
async def select_tariff_plan(callback_query: CallbackQuery, session: Any, state: FSMContext):
    """Обрабатывает выбор тарифа пользователем."""
    tg_id = callback_query.from_user.id
    tariff_id = int(callback_query.data.split("|")[1])

    logger.info("[TARIFF_CFG] select_tariff_plan: tg_id=%s tariff_id=%s", tg_id, tariff_id)

    tariff = await get_tariff_by_id(session, tariff_id)
    if not tariff:
        await edit_or_send_message(
            target_message=callback_query.message,
            text="❌ Указанный тариф не найден.",
        )
        await callback_query.answer()
        logger.warning(f"[TARIFF_CFG] select_tariff_plan tariff_not_found: tariff_id={tariff_id}")
        return

    discount_info = await check_hot_lead_discount(session, tg_id)
    if tariff.get("group_code") in ["discounts", "discounts_max"]:
        if not discount_info.get("available") or datetime.utcnow() >= discount_info["expires_at"]:
            builder = InlineKeyboardBuilder()
            builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
            await edit_or_send_message(
                target_message=callback_query.message,
                text="❌ Скидка недоступна или истекла. Пожалуйста, выберите тариф заново.",
                reply_markup=builder.as_markup(),
            )
            await callback_query.answer()
            logger.info(
                "[TARIFF_CFG] select_tariff_plan discount_invalid: "
                f"tg_id={tg_id} tariff_id={tariff_id} info={discount_info}"
            )
            return

    validity_result = await process_check_discount_validity(
        chat_id=tg_id,
        admin=False,
        session=session,
        tariff_group=tariff.get("group_code"),
    )
    if validity_result:
        builder = InlineKeyboardBuilder()
        builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
        await edit_or_send_message(
            target_message=callback_query.message,
            text=validity_result["message"],
            reply_markup=builder.as_markup(),
        )
        await callback_query.answer()
        logger.info(
            "[TARIFF_CFG] select_tariff_plan discount_validity_failed: "
            f"tg_id={tg_id} tariff_id={tariff_id} result={validity_result}"
        )
        return

    if tariff.get("configurable"):
        logger.info(f"[TARIFF_CFG] select_tariff_plan configurable: tg_id={tg_id} tariff_id={tariff_id}")
        try:
            await start_user_tariff_configurator(callback_query, session=session, state=state, tariff=tariff)
        except Exception as error:
            logger.error(f"[TARIFF_CFG] error_in_configurator: tariff_id={tariff_id} error={error}")
            await edit_or_send_message(
                target_message=callback_query.message,
                text="❌ Ошибка конфигурации тарифа. Попробуйте позже.",
                reply_markup=None,
            )
        return

    duration_days = int(tariff.get("duration_days") or 30)
    price_rub = int(tariff.get("price_rub") or 0)
    selected_device_limit = tariff.get("device_limit")

    raw_traffic_limit = tariff.get("traffic_limit")
    selected_traffic_gb = None
    if raw_traffic_limit:
        raw_traffic_limit = int(raw_traffic_limit)
        if raw_traffic_limit >= GB:
            selected_traffic_gb = int(raw_traffic_limit / GB)
        else:
            selected_traffic_gb = raw_traffic_limit

    logger.info(
        "[TARIFF_CFG] select_tariff_plan fixed_tariff: "
        f"tg_id={tg_id} tariff_id={tariff_id} duration_days={duration_days} "
        f"price_rub={price_rub} device_limit={selected_device_limit} "
        f"selected_traffic_gb={selected_traffic_gb}"
    )

    await proceed_purchase_with_values(
        callback_query=callback_query,
        session=session,
        state=state,
        tariff=tariff,
        duration_days=duration_days,
        price_rub=price_rub,
        selected_device_limit=selected_device_limit,
        selected_traffic_gb=selected_traffic_gb,
    )


@router.callback_query(
    F.data.startswith("cfg_user_devices|"),
    TariffUserConfigState.configuring,
)
async def handle_user_devices_choice(callback: CallbackQuery, state: FSMContext, session: Any):
    """Обрабатывает выбор лимита устройств в конфигураторе."""
    _, _tariff_id_str, devices_str = callback.data.split("|", 2)
    devices = int(devices_str)

    current = (await state.get_data()).get("config_selected_device_limit")
    if current is not None and int(current) == devices:
        await callback.answer()
        return

    await state.update_data(config_selected_device_limit=devices)
    await render_user_config_screen(callback, state, session)


@router.callback_query(
    F.data.startswith("cfg_user_traffic|"),
    TariffUserConfigState.configuring,
)
async def handle_user_traffic_choice(callback: CallbackQuery, state: FSMContext, session: Any):
    """Обрабатывает выбор лимита трафика в конфигураторе."""
    _, _tariff_id_str, traffic_str = callback.data.split("|", 2)
    traffic = int(traffic_str)

    current = (await state.get_data()).get("config_selected_traffic_gb")
    if current is not None and int(current) == traffic:
        await callback.answer()
        return

    await state.update_data(config_selected_traffic_gb=traffic)
    await render_user_config_screen(callback, state, session=session)


@router.callback_query(F.data.startswith("cfg_user_confirm|"), TariffUserConfigState.configuring)
async def handle_user_config_confirm(callback: CallbackQuery, state: FSMContext, session: Any):
    """Подтверждает выбор параметров тарифа и запускает покупку."""
    logger.info(f"[TARIFF_CFG] handle_user_config_confirm: tg_id={callback.from_user.id}")
    await finalize_config_and_purchase(callback, state, session=session)
