from __future__ import annotations

from pathlib import Path
from typing import Any, Callable

from .pins import PinReadMessage

__all__ = ["WokwiClientSync"]

class WokwiClientSync:
    """
    Synchronous client for the Wokwi Simulation API.

    This stub provides precise types for IDEs and type checkers. The runtime
    implementation mirrors the async API of `WokwiClient`, but executes calls
    synchronously by delegating to an internal event loop.
    """

    version: str
    last_pause_nanos: int

    def __init__(self, token: str, server: str | None = None) -> None: ...

    # Context manager
    def __enter__(self) -> WokwiClientSync: ...
    def __exit__(self, exc_type: type, exc_val: Exception, exc_tb: Any) -> None: ...

    # Lifecycle
    def connect(self) -> dict[str, Any]: ...
    def disconnect(self) -> None: ...

    # Serial monitoring (non-blocking background tasks managed internally)
    def serial_monitor(self, callback: Callable[[bytes], Any]) -> None: ...
    def serial_monitor_cat(self, decode_utf8: bool = True, errors: str = "replace") -> None: ...
    def stop_serial_monitors(self) -> None: ...

    # Methods mirrored from WokwiClient (sync variants)
    def upload(self, name: str, content: bytes) -> None: ...
    def upload_file(self, filename: str, local_path: Path | None = None) -> None: ...
    def download(self, name: str) -> bytes: ...
    def download_file(self, name: str, local_path: Path | None = None) -> None: ...
    def start_simulation(
        self,
        firmware: str,
        elf: str | None = None,
        pause: bool = False,
        chips: list[str] = ...,  # default empty list at runtime
    ) -> None: ...
    def pause_simulation(self) -> None: ...
    def resume_simulation(self, pause_after: int | None = None) -> None: ...
    def wait_until_simulation_time(self, seconds: float) -> None: ...
    def restart_simulation(self, pause: bool = False) -> None: ...
    def serial_write(self, data: bytes | str | list[int]) -> None: ...
    def read_pin(self, part: str, pin: str) -> PinReadMessage: ...
    def listen_pin(self, part: str, pin: str, listen: bool = True) -> None: ...
    def gpio_list(self) -> list[str]: ...
    def set_control(self, part: str, control: str, value: int | bool | float) -> None: ...
    def read_framebuffer_png_bytes(self, id: str) -> bytes: ...
    def save_framebuffer_png(self, id: str, path: Path, overwrite: bool = True) -> Path: ...
