import asyncio
import threading
from typing import Any, Coroutine, TypeVar, Optional
import atexit

T = TypeVar("T")


class AsyncExecutor:
    """
    Simple async executor for pywebview.

    Design principles:
    1. Single instance, created before webview.start()
    2. One dedicated background thread with event loop
    3. Thread-safe by asyncio's design, no locks needed
    """

    _instance = None

    def __new__(cls):
        """Singleton pattern - simple and sufficient"""
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        """Initialize once"""
        if self._initialized:
            return

        self._initialized = True
        self._loop: asyncio.AbstractEventLoop = asyncio.new_event_loop()
        self._thread: threading.Thread | None = None

        # Start background thread with event loop
        self._start_loop()
        atexit.register(self._cleanup)

    def _start_loop(self):
        """Start event loop in background thread"""

        def run_loop():
            asyncio.set_event_loop(self._loop)
            self._loop.run_forever()

        self._thread = threading.Thread(
            target=run_loop, name="AsyncExecutor", daemon=True
        )
        self._thread.start()

    def run_and_wait(
        self, coro: Coroutine[Any, Any, T], timeout: Optional[float] = None
    ) -> T:
        """
        Execute coroutine and wait (BLOCKING).
        Use with caution in pywebview events.
        """
        future = asyncio.run_coroutine_threadsafe(coro, self._loop)
        return future.result(timeout=timeout)

    def _cleanup(self):
        """Clean shutdown"""
        if self._loop and self._loop.is_running():
            self._loop.call_soon_threadsafe(self._loop.stop)

        if self._thread and self._thread.is_alive():
            self._thread.join(timeout=2)
