import asyncio
import time
from collections.abc import Callable
from typing import Any


class TaskQueue:
    def __init__(self, max_concurrent: int = 3, event_bus=None):
        self.queue: asyncio.Queue = asyncio.Queue()
        self.semaphore = asyncio.Semaphore(max_concurrent)
        self.max_concurrent = max_concurrent
        self.active_tasks: dict[str, dict[str, Any]] = {}
        self.event_bus = event_bus
        self._workers: list[asyncio.Task] = []
        self._running = False

    def start(self, worker_count: int = 3):
        if self._running:
            return
        self._running = True
        try:
            loop = asyncio.get_event_loop()
        except RuntimeError:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
        for i in range(worker_count):
            t = loop.create_task(self._worker_loop(i))
            self._workers.append(t)

    async def enqueue(self, task_id: str, payload: dict[str, Any], handler: Callable | None = None):
        item = {"task_id": task_id, "payload": payload, "handler": handler, "enqueued_at": time.time()}
        await self.queue.put(item)

    async def _worker_loop(self, worker_id: int):
        while self._running:
            try:
                item = await self.queue.get()
                task_id = item["task_id"]
                payload = item["payload"]
                handler = item["handler"]

                async with self.semaphore:
                    self.active_tasks[task_id] = {"worker_id": worker_id, "status": "running", "started_at": time.time()}
                    try:
                        if handler:
                            if asyncio.iscoroutinefunction(handler):
                                await handler(task_id, payload)
                            else:
                                handler(task_id, payload)
                        else:
                            await asyncio.sleep(1)
                    except Exception:
                        pass
                    finally:
                        self.active_tasks.pop(task_id, None)
                self.queue.task_done()
            except asyncio.CancelledError:
                break
            except Exception:
                pass

    def get_status(self) -> dict[str, Any]:
        return {
            "queued_count": self.queue.qsize(),
            "active_count": len(self.active_tasks),
            "active_tasks": self.active_tasks,
            "max_concurrent": self.max_concurrent
        }
