from __future__ import annotations

import asyncio
from dataclasses import dataclass

from app.services.chat_queue_redis_service import redis_chat_queue_manager
from app.services.chat_queue_service import ChatQueueConfig, QueueRequest, chat_queue_manager
from app.services.redis_client import ping_redis


@dataclass
class ChatQueueLease:
    backend: str
    request: QueueRequest


async def request_chat_slot(config: ChatQueueConfig) -> ChatQueueLease:
    if await ping_redis():
        try:
            return ChatQueueLease("redis", await redis_chat_queue_manager.request_slot(config))
        except Exception:
            pass
    request = await asyncio.to_thread(chat_queue_manager.request_slot, config)
    return ChatQueueLease("memory", request)


async def wait_for_chat_slot(lease: ChatQueueLease, config: ChatQueueConfig) -> ChatQueueLease:
    token = lease.request.token
    if lease.backend == "redis" and isinstance(token, str):
        try:
            lease.request = await redis_chat_queue_manager.wait_for_slot(token, config)
            return lease
        except Exception:
            await cancel_chat_waiter(lease)
            lease.backend = "memory"
            lease.request = await asyncio.to_thread(chat_queue_manager.request_slot, config)
            if lease.request.status == "queued":
                lease.request = await asyncio.to_thread(chat_queue_manager.wait_for_slot, lease.request.token, config)
            return lease

    lease.request = await asyncio.to_thread(chat_queue_manager.wait_for_slot, token, config)
    return lease


async def cancel_chat_waiter(lease: ChatQueueLease) -> None:
    token = lease.request.token
    if lease.backend == "redis" and isinstance(token, str):
        try:
            await redis_chat_queue_manager.cancel_waiter(token)
        except Exception:
            pass
        return
    if token is not None:
        await asyncio.to_thread(chat_queue_manager.cancel_waiter, token)


async def release_chat_slot(lease: ChatQueueLease) -> None:
    token = lease.request.token
    if lease.backend == "redis" and isinstance(token, str):
        try:
            await redis_chat_queue_manager.release_slot(token)
        except Exception:
            pass
        return
    await asyncio.to_thread(chat_queue_manager.release_slot)
