import pygame
import typing
import kivy.clock as _kc
import pykimix.pygame_surface as _ps

class BridgeConfig:
    def __init__(self, size: typing.Tuple[int, int], fps: int = 60, double_buffer: bool = True, scale_mode: str = "stretch", input_map: typing.Optional[dict] = None):
        self.size = size
        self.fps = fps
        self.double_buffer = double_buffer
        self.scale_mode = scale_mode
        self.input_map = input_map

class PygameAdapter(typing.Protocol):
    def init(self, surface_size: typing.Tuple[int, int]) -> None: ...
    def update(self, dt: float) -> None: ...
    def handle_pygame_event(self, ev: typing.Any) -> None: ...
    def get_surface(self) -> "pygame.Surface": ...

class _DefaultAdapter:
    def __init__(self):
        self._surface = None
        self._running = True
    def init(self, surface_size: typing.Tuple[int, int]) -> None:
        pygame.init()
        self._surface = pygame.Surface(surface_size, pygame.SRCALPHA, 32)
    def update(self, dt: float) -> None:
        pass
    def handle_pygame_event(self, ev: typing.Any) -> None:
        if hasattr(ev, "type"):
            try:
                if ev.type == pygame.QUIT:
                    self._running = False
            except Exception:
                pass
    def get_surface(self) -> "pygame.Surface":
        return self._surface

class Bridge:
    def __init__(self, adapter: typing.Optional[PygameAdapter] = None, config: typing.Optional[BridgeConfig] = None):
        if config is None:
            config = BridgeConfig((640, 480))
        self.config = config
        if adapter is None:
            adapter = _DefaultAdapter()
        self.adapter = adapter
        self._widget = None
        self._ev_handler = None
        self._clock_event = None
        self._running = False
    def start(self) -> None:
        self._running = True
        self.adapter.init(self.config.size)
        self._widget = _ps.PygameWidget(self.config.size[0], self.config.size[1])
        self._widget.size = (self.config.size[0], self.config.size[1])
        self._widget.pos = (0, 0)
        self._clock_event = _kc.Clock.schedule_interval(self._update, 1.0 / float(self.config.fps))
    def stop(self) -> None:
        if self._clock_event is not None:
            try:
                _kc.Clock.unschedule(self._update)
            except Exception:
                pass
            self._clock_event = None
        self._running = False
    def _update(self, dt: float) -> None:
        try:
            for ev in list(pygame.event.get()):
                try:
                    self.adapter.handle_pygame_event(ev)
                except Exception:
                    pass
            try:
                self.adapter.update(dt)
            except Exception:
                pass
            try:
                surf = self.adapter.get_surface()
                if surf is None:
                    surf = self._widget.surface
                if surf is not None:
                    self._widget.surface.blit(surf, (0, 0))
                    self._widget.update()
            except Exception:
                try:
                    self._widget.update()
                except Exception:
                    pass
        except Exception:
            pass
    def post_kivy_event(self, event: dict) -> None:
        try:
            if event is None:
                return
            if event.get("type") == "quit":
                self.stop()
        except Exception:
            pass
    def post_pygame_event(self, pg_event: "pygame.Event") -> None:
        try:
            pygame.event.post(pg_event)
        except Exception:
            pass
    def get_widget(self):
        return self._widget