import uuid

from datetime import datetime

import pytz

from aiogram import Router
from aiogram.types import (
    CallbackQuery,
    InlineKeyboardButton,
    Message,
    WebAppInfo,
)
from aiogram.utils.keyboard import InlineKeyboardBuilder
from sqlalchemy import update

from bot import bot
from config import REMNAWAVE_WEBAPP, SUPPORT_CHAT_URL
from core.bootstrap import BUTTONS_CONFIG, MODES_CONFIG
from database import (
    get_key_details,
    get_trial,
    update_balance,
    update_trial,
)
from database.models import Key
from handlers.buttons import (
    CONNECT_DEVICE,
    MAIN_MENU,
    MY_SUB,
    ROUTER_BUTTON,
    SUPPORT,
    TV_BUTTON,
)
from handlers.keys.operations import create_key_on_cluster
from handlers.tariffs.tariff_display import (
    build_key_created_message,
    get_effective_limits_for_key,
    resolve_price_to_charge,
    resolve_vless_enabled,
)
from handlers.utils import (
    edit_or_send_message,
    generate_random_email,
    get_least_loaded_cluster,
    is_full_remnawave_cluster,
)
from hooks.hook_buttons import insert_hook_buttons
from hooks.processors import (
    process_cluster_override,
    process_intercept_key_creation_message,
    process_key_creation_complete,
    process_remnawave_webapp_override,
)
from logger import logger


router = Router()
moscow_tz = pytz.timezone("Europe/Moscow")


async def key_cluster_mode(
    tg_id: int,
    expiry_time: datetime,
    state,
    session,
    message_or_query: Message | CallbackQuery | None = None,
    plan: int | None = None,
    selected_device_limit: int | None = None,
    selected_traffic_gb: int | None = None,
    selected_price_rub: int | None = None,
):
    target_message = None
    safe_to_edit = False

    if isinstance(message_or_query, CallbackQuery) and message_or_query.message:
        target_message = message_or_query.message
        safe_to_edit = True
    elif isinstance(message_or_query, Message):
        target_message = message_or_query
        safe_to_edit = True

    while True:
        key_name = await generate_random_email(session=session)
        existing_key = await get_key_details(session, key_name)
        if not existing_key:
            break

    client_id = str(uuid.uuid4())
    email = key_name.lower()
    expiry_timestamp = int(expiry_time.timestamp() * 1000)

    try:
        data = await state.get_data() if state else {}
        is_trial = data.get("is_trial", False)

        if selected_device_limit is None:
            selected_device_limit = data.get("config_selected_device_limit") or data.get("selected_device_limit")

        if selected_traffic_gb is None:
            selected_traffic_gb = data.get("config_selected_traffic_gb") or data.get("selected_traffic_limit_gb")

        effective_tariff_id = plan or data.get("tariff_id")

        device_limit, traffic_limit_bytes = await get_effective_limits_for_key(
            session=session,
            tariff_id=effective_tariff_id,
            selected_device_limit=selected_device_limit,
            selected_traffic_gb=selected_traffic_gb,
        )

        forced_cluster = await process_cluster_override(
            tg_id=tg_id,
            state_data=data,
            session=session,
            plan=plan,
        )

        if forced_cluster:
            least_loaded_cluster = forced_cluster
        else:
            try:
                least_loaded_cluster = await get_least_loaded_cluster(session)
            except ValueError as e:
                logger.error(f"Нет доступных кластеров: {e}")
                error_message = str(e)

                if safe_to_edit:
                    await edit_or_send_message(
                        target_message=target_message,
                        text=error_message,
                        reply_markup=None,
                    )
                else:
                    await bot.send_message(chat_id=tg_id, text=error_message)
                return

        if device_limit is None:
            device_limit = 0
        if traffic_limit_bytes is None:
            traffic_limit_bytes = 0

        if selected_price_rub is not None:
            price_to_charge = selected_price_rub
        else:
            price_to_charge = await resolve_price_to_charge(session, data)

        await create_key_on_cluster(
            cluster_id=least_loaded_cluster,
            tg_id=tg_id,
            client_id=client_id,
            email=email,
            expiry_timestamp=expiry_timestamp,
            plan=plan,
            session=session,
            hwid_limit=device_limit,
            traffic_limit_bytes=traffic_limit_bytes,
            is_trial=is_trial,
        )

        logger.info(f"[Key Creation] Ключ создан на кластере {least_loaded_cluster} для пользователя {tg_id}")

        await session.execute(
            update(Key)
            .where(Key.tg_id == tg_id, Key.email == email)
            .values(
                selected_device_limit=selected_device_limit,
                selected_traffic_limit=selected_traffic_gb,
                selected_price_rub=price_to_charge,
            )
        )
        await session.commit()

        key_record = await get_key_details(session, email)
        if not key_record:
            raise ValueError(f"Ключ не найден после создания: {email}")

        final_link = key_record.get("link", "")

        if is_trial:
            trial_status = await get_trial(session, tg_id)
            if trial_status in [0, -1]:
                await update_trial(session, tg_id, 1)

        if price_to_charge:
            await update_balance(session, tg_id, -int(price_to_charge))

    except Exception as e:
        logger.error(f"[Error] Ошибка при создании ключа для пользователя {tg_id}: {e}")
        error_message = "❌ Произошла ошибка при создании подписки. Пожалуйста, попробуйте снова."

        if safe_to_edit:
            await edit_or_send_message(
                target_message=target_message,
                text=error_message,
                reply_markup=None,
            )
        else:
            await bot.send_message(chat_id=tg_id, text=error_message)
        return

    vless_enabled = False
    try:
        if plan:
            vless_enabled = await resolve_vless_enabled(session, plan)
        elif key_record.get("tariff_id"):
            vless_enabled = await resolve_vless_enabled(session, key_record["tariff_id"])
    except Exception:
        vless_enabled = False

    tv_button_enabled = bool(BUTTONS_CONFIG.get("ANDROID_TV_BUTTON_ENABLE"))

    builder = InlineKeyboardBuilder()
    if vless_enabled:
        builder.row(InlineKeyboardButton(text=ROUTER_BUTTON, callback_data=f"connect_router|{key_name}"))
    else:
        if await is_full_remnawave_cluster(least_loaded_cluster, session):
            use_webapp = bool(MODES_CONFIG.get("REMNAWAVE_WEBAPP_ENABLED", REMNAWAVE_WEBAPP))
            if use_webapp and final_link:
                use_webapp = await process_remnawave_webapp_override(
                    remnawave_webapp=use_webapp,
                    final_link=final_link,
                    session=session,
                )

            if (
                use_webapp
                and final_link
                and isinstance(final_link, str)
                and final_link.startswith(("http://", "https://"))
            ):
                builder.row(InlineKeyboardButton(text=CONNECT_DEVICE, web_app=WebAppInfo(url=final_link)))
                if tv_button_enabled:
                    builder.row(InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{email}"))
            else:
                builder.row(InlineKeyboardButton(text=CONNECT_DEVICE, callback_data=f"connect_device|{key_name}"))
        else:
            builder.row(InlineKeyboardButton(text=CONNECT_DEVICE, callback_data=f"connect_device|{key_name}"))

    builder.row(InlineKeyboardButton(text=MY_SUB, callback_data=f"view_key|{key_name}"))
    builder.row(InlineKeyboardButton(text=SUPPORT, url=SUPPORT_CHAT_URL))
    builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))

    if await process_intercept_key_creation_message(
        chat_id=tg_id,
        session=session,
        target_message=message_or_query,
    ):
        return

    hook_commands = await process_key_creation_complete(
        chat_id=tg_id,
        admin=False,
        session=session,
        email=email,
        key_name=key_name,
    )
    if hook_commands:
        builder = insert_hook_buttons(builder, hook_commands)

    key_message_text = await build_key_created_message(
        session=session,
        key_record=key_record,
        final_link=final_link,
        selected_device_limit=selected_device_limit,
        selected_traffic_gb=selected_traffic_gb,
    )

    default_media_path = "img/pic.jpg"
    if safe_to_edit:
        await edit_or_send_message(
            target_message=target_message,
            text=key_message_text,
            reply_markup=builder.as_markup(),
            media_path=default_media_path,
        )
    else:
        await bot.send_message(
            chat_id=tg_id,
            text=key_message_text,
            reply_markup=builder.as_markup(),
        )

    if state:
        await state.clear()
