import asyncio
import ctypes
from collections.abc import Callable
from collections.abc import Iterable
from datetime import timedelta
from types import TracebackType
from typing import TYPE_CHECKING
from typing import Generic
from typing import Self
from typing import TypeVar
import numpy as np
from pyautd3.autd_error import InvalidDatagramTypeError
from pyautd3.autd_error import KeyAlreadyExistsError
from pyautd3.controller.timer import SpinSleeper
from pyautd3.controller.timer import TimerStrategy
from pyautd3.derive import builder
from pyautd3.driver.autd3_device import AUTD3
from pyautd3.driver.datagram import Datagram
from pyautd3.driver.firmware.fpga import FPGAState
from pyautd3.driver.firmware_version import FirmwareInfo
from pyautd3.driver.geometry import Device
from pyautd3.driver.geometry import Geometry
from pyautd3.driver.link import Link
from pyautd3.driver.link import LinkBuilder
from pyautd3.native_methods.autd3capi import ControllerBuilderPtr
from pyautd3.native_methods.autd3capi import ControllerPtr
from pyautd3.native_methods.autd3capi import RuntimePtr
from pyautd3.native_methods.autd3capi import NativeMethods as Base
from pyautd3.native_methods.autd3capi_driver import DatagramPtr
from pyautd3.native_methods.autd3capi_driver import GeometryPtr
from pyautd3.native_methods.autd3capi_driver import HandlePtr
from pyautd3.native_methods.autd3capi_driver import TimerStrategyWrap
from pyautd3.native_methods.structs import FfiFuture
from pyautd3.native_methods.structs import Quaternion
from pyautd3.native_methods.structs import Vector3
from pyautd3.native_methods.utils import _validate_ptr
from pyautd3.native_methods.utils import _validate_status
from pyautd3.emulator import Emulator
from pyautd3.emulator import Recorder

K = TypeVar("K")
L = TypeVar("L", bound=Link)

class _Builder():
    devices: list[AUTD3]
    async def open_async(self: _Builder, link: LinkBuilder[L]) -> Controller[L]: ...
    def __init__(self: _Builder, iterable: Iterable[AUTD3]) -> None: ...
    def _ptr(self: _Builder, ) -> ControllerBuilderPtr: ...
    def open(self: _Builder, link: LinkBuilder[L]) -> Controller[L]: ...
    def into_emulator(self: _Builder, ) -> Emulator: ...
    def with_fallback_parallel_threshold(self: _Builder, fallback_parallel_threshold: int) -> _Builder: ...
    def with_fallback_timeout(self: _Builder, fallback_timeout: timedelta) -> _Builder: ...
    def with_send_interval(self: _Builder, send_interval: timedelta) -> _Builder: ...
    def with_receive_interval(self: _Builder, receive_interval: timedelta) -> _Builder: ...
    def with_timer_strategy(self: _Builder, timer_strategy: TimerStrategyWrap) -> _Builder: ...
    @property
    def fallback_parallel_threshold(self: _Builder) -> int: ...
    @property
    def fallback_timeout(self: _Builder) -> timedelta: ...
    @property
    def send_interval(self: _Builder) -> timedelta: ...
    @property
    def receive_interval(self: _Builder) -> timedelta: ...
    @property
    def timer_strategy(self: _Builder) -> TimerStrategyWrap: ...

class _GroupGuard(Generic[K]):
    _controller: Controller
    _keys: list[int]
    _datagrams: list[DatagramPtr]
    _keymap: dict[K, int]
    _k: int
    async def send_async(self: _GroupGuard[K], ) -> None: ...
    def __init__(self: _GroupGuard[K], group_map: Callable[[Device], K | None], controller: Controller) -> None: ...
    def set(self: _GroupGuard[K], key: K, d: Datagram | tuple[Datagram, Datagram]) -> _GroupGuard[K]: ...
    def send(self: _GroupGuard[K], ) -> None: ...

class Controller(Geometry, Generic[L]):
    _runtime: RuntimePtr
    _handle: HandlePtr
    _ptr: ControllerPtr
    _link: L
    _disposed: bool
    async def _open_impl_async(self: Controller[L], link_builder: LinkBuilder[L], timeout: timedelta | None = None) -> Controller[L]: ...
    async def firmware_version_async(self: Controller[L], ) -> list[FirmwareInfo]: ...
    async def close_async(self: Controller[L], ) -> None: ...
    async def fpga_state_async(self: Controller[L], ) -> list[FPGAState | None]: ...
    async def send_async(self: Controller[L], d: Datagram | tuple[Datagram, Datagram]) -> None: ...
    def __init__(self: Controller[L], geometry: GeometryPtr, runtime: RuntimePtr, handle: HandlePtr, ptr: ControllerPtr, link: L) -> None: ...
    def __del__(self: Controller[L], ) -> None: ...
    def _dispose(self: Controller[L], ) -> None: ...
    def __enter__(self: Controller[L], ) -> Controller[L]: ...
    def __exit__(self: Controller[L], _exc_type: type[BaseException] | None, _exc_value: BaseException | None, _traceback: TracebackType | None) -> None: ...
    def firmware_version(self: Controller[L], ) -> list[FirmwareInfo]: ...
    def close(self: Controller[L], ) -> None: ...
    def fpga_state(self: Controller[L], ) -> list[FPGAState | None]: ...
    def send(self: Controller[L], d: Datagram | tuple[Datagram, Datagram]) -> None: ...
    def group(self: Controller[L], group_map: Callable[[Device], K | None]) -> _GroupGuard: ...
    def tick(self: Controller[L], tick: timedelta) -> None: ...
    @staticmethod
    def builder(iterable: Iterable[AUTD3]) -> _Builder: ...
    @staticmethod
    def _open_impl(builder: ControllerBuilderPtr, link_builder: LinkBuilder[L], timeout: timedelta | None) -> Controller[L]: ...
    @property
    def link(self: Controller[L]) -> L: ...
    @property
    def geometry(self: Controller[L]) -> Geometry: ...
