import asyncio
from threading import Thread

from a2wsgi import ASGIMiddleware
from asgi_lifespan import LifespanManager
from fastapi import FastAPI


class PassengerRuntime:
    """Jalankan lifespan dan request ASGI pada event loop yang sama."""

    def __init__(self, app: FastAPI) -> None:
        self.loop = asyncio.new_event_loop()
        self.thread = Thread(
            target=self.loop.run_forever, name="neoerp-passenger", daemon=True
        )
        self.thread.start()
        started = False
        try:
            self.manager = asyncio.run_coroutine_threadsafe(
                self._startup(app), self.loop
            ).result()
            self.application = ASGIMiddleware(self.manager.app, loop=self.loop)
            started = True
        finally:
            if not started:
                self._stop_loop()

    async def _startup(self, app: FastAPI) -> LifespanManager:
        manager = LifespanManager(app, startup_timeout=10, shutdown_timeout=10)
        await manager.__aenter__()
        return manager

    async def _shutdown(self) -> None:
        await self.manager.__aexit__(None, None, None)

    def _stop_loop(self) -> None:
        self.loop.call_soon_threadsafe(self.loop.stop)
        self.thread.join()
        self.loop.close()

    def close(self) -> None:
        if self.loop.is_closed():
            return
        try:
            asyncio.run_coroutine_threadsafe(self._shutdown(), self.loop).result()
        finally:
            self._stop_loop()
