# sedsnet.pyi
# =============================
# Auto-generated Python type stubs for sedsnet. DO NOT EDIT AS CHANGES WILL BE OVERWRITTEN.
# =============================
from __future__ import annotations

from typing import Any, Callable, Optional, Sequence, Tuple, List, Dict, Literal, Union
from enum import IntEnum
from collections.abc import Buffer  # Python 3.12 buffer protocol typing


# ==============================
# Public enums / constants (parity with C header)
# ==============================

from enum import IntEnum

/* {{AUTOGEN:PY_ENUMS}} */

class ElemKind(IntEnum):
    """Element kind for generic logging (C API parity)."""
    UNSIGNED: int  #: Unsigned integers (u8/u16/u32/u64).
    SIGNED: int    #: Signed integers (i8/i16/i32/i64).
    FLOAT: int     #: Floating-point (f32/f64).


class RouterMode(IntEnum):
    Relay: int
    Sink: int


class RouteSelectionMode(IntEnum):
    Fanout: int
    Weighted: int
    Failover: int


# ==============================
# Callback protocols (informal)
# ==============================

TxCallback = Callable[[bytes], None]
"""Transmit callback. Called as tx(bytes)."""

NowMsCallback = Callable[[], int]
"""Clock callback returning monotonic milliseconds."""

PacketHandler = Callable[["Packet"], None]
"""Endpoint handler invoked with (Packet)."""

PackedHandler = Callable[[bytes], None]
"""Endpoint handler invoked with (bytes)."""

SideId = int
"""Logical relay side index (e.g. CAN, UART, RADIO)."""

# ==============================
# Packet object (immutable view of a telemetry packet)
# ==============================

class Packet:
    """
    Immutable, heap-backed telemetry packet.

    Attributes:
        ty:           DataType as an int (use DataType(...) to coerce).
        data_size:    Declared schema payload size (bytes).
        sender:       Sender string from the packet header.
        endpoints:    List of DataEndpoint values as ints.
        timestamp_ms: Packet timestamp in milliseconds (u64).
        payload:      Raw payload bytes (already validated for size/schema).
    """

    @property
    def ty(self) -> int: ...
    @property
    def data_size(self) -> int: ...
    @property
    def sender(self) -> str: ...
    @property
    def endpoints(self) -> List[int]: ...
    @property
    def timestamp_ms(self) -> int: ...
    @property
    def payload(self) -> bytes: ...

    def header_string(self) -> str: ...
    def __str__(self) -> str: ...
    def wire_size(self) -> int: ...
    def pack(self) -> bytes: ...

    # Typed payload decoders (mirror Packet::data_as_*)
    def data_as_u8(self) -> List[int]: ...
    def data_as_u16(self) -> List[int]: ...
    def data_as_u32(self) -> List[int]: ...
    def data_as_u64(self) -> List[int]: ...

    def data_as_i8(self) -> List[int]: ...
    def data_as_i16(self) -> List[int]: ...
    def data_as_i32(self) -> List[int]: ...
    def data_as_i64(self) -> List[int]: ...

    def data_as_f32(self) -> List[float]: ...
    def data_as_f64(self) -> List[float]: ...

    def data_as_bool(self) -> List[bool]: ...
    def data_as_string(self) -> str: ...

# ==============================
# Router (lifecycle, logging, queues)
# ==============================

class Router:
    @staticmethod
    def new_singleton(
        now_ms: Optional[NowMsCallback] = ...,
        handlers: Optional[
            Sequence[Tuple[int, Optional[PacketHandler], Optional[PackedHandler]]]
        ] = ...,
        timesync_enabled: bool = ...,
        e2e_mode: int = 255,
        e2e_key_id: int = ...,
    ) -> "Router": ...
    """
        Create or retrieve a per-process singleton Router.

        The first call creates the singleton with the given `now_ms`/`handlers`.
        If `now_ms` is omitted on `std` builds, Router uses its own internal monotonic clock.
        Subsequent calls return another
        Router object wrapping the same underlying singleton instance.

        Passing non-None arguments after the singleton has already been created
        will raise a RuntimeError.
        """

    def __init__(
        self,
        now_ms: Optional[NowMsCallback] = ...,
        handlers: Optional[
            Sequence[Tuple[int, Optional[PacketHandler], Optional[PackedHandler]]]
        ] = ...,
        timesync_enabled: bool = ...,
        e2e_mode: int = 255,
        e2e_key_id: int = ...,
    ) -> None: ...
    @property
    def sender_id(self) -> str: ...
    def set_sender_id(self, sender_id: str) -> None: ...

    def log_bytes(
        self,
        ty: int,
        data: Buffer | bytes | bytearray | memoryview,
        timestamp_ms: Optional[int] = ...,
        queue: bool = ...,
    ) -> None: ...

    def log_f32(
        self,
        ty: int,
        values: Sequence[float] | Buffer | bytes | bytearray | memoryview,
        timestamp_ms: Optional[int] = ...,
        queue: bool = ...,
    ) -> None: ...

    def log(
        self,
        ty: int,
        data: Buffer | bytes | bytearray | memoryview | str,
        elem_size: Literal[1, 2, 4, 8],
        elem_kind: Literal[ElemKind.UNSIGNED, ElemKind.SIGNED, ElemKind.FLOAT, 0, 1, 2],
        timestamp_ms: Optional[int] = ...,
        queue: bool = ...,
    ) -> None: ...

    def add_side_packed(self, name: str, tx: Callable[[bytes], None], reliable_enabled: bool = ...) -> SideId: ...
    def add_side_packet(self, name: str, tx: Callable[[Packet], None], reliable_enabled: bool = ...) -> SideId: ...
    def remove_side(self, side_id: SideId) -> None: ...
    def set_side_ingress_enabled(self, side_id: SideId, enabled: bool) -> None: ...
    def set_side_egress_enabled(self, side_id: SideId, enabled: bool) -> None: ...
    def set_route(self, src_side_id: Optional[SideId], dst_side_id: SideId, enabled: bool) -> None: ...
    def clear_route(self, src_side_id: Optional[SideId], dst_side_id: SideId) -> None: ...
    def set_typed_route(self, src_side_id: Optional[SideId], ty: int | DataType, dst_side_id: SideId, enabled: bool) -> None: ...
    def clear_typed_route(self, src_side_id: Optional[SideId], ty: int | DataType, dst_side_id: SideId) -> None: ...
    def set_source_route_mode(self, src_side_id: Optional[SideId], mode: int | RouteSelectionMode) -> None: ...
    def clear_source_route_mode(self, src_side_id: Optional[SideId]) -> None: ...
    def set_route_weight(self, src_side_id: Optional[SideId], dst_side_id: SideId, weight: int) -> None: ...
    def clear_route_weight(self, src_side_id: Optional[SideId], dst_side_id: SideId) -> None: ...
    def set_route_priority(self, src_side_id: Optional[SideId], dst_side_id: SideId, priority: int) -> None: ...
    def clear_route_priority(self, src_side_id: Optional[SideId], dst_side_id: SideId) -> None: ...

    # Broadcast methods
    def transmit_message_queue(self, packet: Packet) -> None: ...
    def transmit_message(self, packet: Packet) -> None: ...
    def transmit_packed_message(self, data: Buffer | bytes | bytearray | memoryview) -> None: ...
    def transmit_packed_message_queue(self, data: Buffer | bytes | bytearray | memoryview) -> None: ...
    def receive_packed(self, data: Buffer | bytes | bytearray | memoryview) -> None: ...
    def receive_packet(self, packet: Packet) -> None: ...
    def receive_packed_queue(self, data: Buffer | bytes | bytearray | memoryview) -> None: ...
    def receive_packet_queue(self, packet: Packet) -> None: ...

    # Side-aware receive methods
    def receive_packed_from_side(self, side_id: SideId, data: Buffer | bytes | bytearray | memoryview) -> None: ...
    def receive_packet_from_side(self, side_id: SideId, packet: Packet) -> None: ...
    def receive_packed_queue_from_side(self, side_id: SideId, data: Buffer | bytes | bytearray | memoryview) -> None: ...
    def receive_packet_queue_from_side(self, side_id: SideId, packet: Packet) -> None: ...

    # Queue processing
    def process_send_queue(self) -> None: ...
    def process_received_queue(self) -> None: ...
    def process_all_queues(self) -> None: ...
    def clear_rx_queue(self) -> None: ...
    def clear_tx_queue(self) -> None: ...
    def clear_queues(self) -> None: ...

    def process_tx_queue_with_timeout(self, timeout_ms: int) -> None: ...
    def process_rx_queue_with_timeout(self, timeout_ms: int) -> None: ...
    def process_all_queues_with_timeout(self, timeout_ms: int) -> None: ...
    def periodic(self, timeout_ms: int) -> None: ...
    def periodic_no_timesync(self, timeout_ms: int) -> None: ...
    def poll_timesync(self) -> bool: ...
    def announce_discovery(self) -> None: ...
    def poll_discovery(self) -> bool: ...
    def export_topology(self) -> Dict[str, Any]: ...
    def export_runtime_stats(self) -> Dict[str, Any]: ...
    def network_time_ms(self) -> Optional[int]: ...
    def network_time(self) -> Optional[Dict[str, int]]: ...
    def set_local_network_time(
        self,
        year: Optional[int] = ...,
        month: Optional[int] = ...,
        day: Optional[int] = ...,
        hour: Optional[int] = ...,
        minute: Optional[int] = ...,
        second: Optional[int] = ...,
        nanosecond: Optional[int] = ...,
    ) -> None: ...
    def set_local_network_date(self, year: int, month: int, day: int) -> None: ...
    def set_local_network_time_hm(self, hour: int, minute: int) -> None: ...
    def set_local_network_time_hms(self, hour: int, minute: int, second: int) -> None: ...
    def set_local_network_time_hms_millis(self, hour: int, minute: int, second: int, millisecond: int) -> None: ...
    def set_local_network_time_hms_nanos(self, hour: int, minute: int, second: int, nanosecond: int) -> None: ...
    def set_local_network_datetime(self, year: int, month: int, day: int, hour: int, minute: int, second: int) -> None: ...
    def set_local_network_datetime_millis(self, year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) -> None: ...
    def set_local_network_datetime_nanos(self, year: int, month: int, day: int, hour: int, minute: int, second: int, nanosecond: int) -> None: ...

# ==============================
# Relay (fan-out of packed packets)
# ==============================

class Relay:
    """
    Packed-packet relay.

    The Relay:
        - fans out packed telemetry packets from one side to all others
        - has RX and TX queues (same pattern as Router)
        - supports time-budgeted queue processing
        - uses an optional monotonic clock callback for timeout-aware processing
    """
    def __init__(self, now_ms: Optional[NowMsCallback] = ...) -> None: ...
    """
        Create a new Relay.

        Parameters
        ----------
        now_ms:
            Optional zero-arg callback returning an integer timestamp in ms.
            If None, timeouts are based on a default clock that returns 0.
        """
    @property
    def sender_id(self) -> str: ...
    def set_sender_id(self, sender_id: str) -> None: ...

    def add_side_packed(self, name: str, tx: Callable[[bytes], None], reliable_enabled: bool = ...) -> SideId: ...
    """
        Add a new relay side (e.g. 'CAN', 'UART', 'RADIO').

        Parameters
        ----------
        name:
            Human-readable name for this side (used for debugging).
        tx:
            Transmit callback. Called as ``tx(bytes)`` when the relay
            wants to send data on this side.

        Returns
        -------
        SideId
            Integer side id to use with ``rx_packed_from_side``.
        """
    def add_side_packet(self, name: str, tx: Callable[[Packet], None], reliable_enabled: bool = ...) -> SideId: ...
    """
        Add a new side with a packet-based TX callback.

        Parameters
        ----------
        name:
            Human-readable name for this side (used for debugging).
        tx:
            Transmit callback. Called as ``tx(pkt: Packet)`` when the relay
            wants to send a Packet on this side.

        Returns
        -------
        SideId
            Integer side id to use with ``rx_packed_from_side`` and ``rx_packet_from_side``.
        """
    def remove_side(self, side_id: SideId) -> None: ...
    def set_side_ingress_enabled(self, side_id: SideId, enabled: bool) -> None: ...
    def set_side_egress_enabled(self, side_id: SideId, enabled: bool) -> None: ...
    def set_route(self, src_side_id: Optional[SideId], dst_side_id: SideId, enabled: bool) -> None: ...
    def clear_route(self, src_side_id: Optional[SideId], dst_side_id: SideId) -> None: ...
    def set_typed_route(self, src_side_id: Optional[SideId], ty: int | DataType, dst_side_id: SideId, enabled: bool) -> None: ...
    def clear_typed_route(self, src_side_id: Optional[SideId], ty: int | DataType, dst_side_id: SideId) -> None: ...
    def set_source_route_mode(self, src_side_id: Optional[SideId], mode: int | RouteSelectionMode) -> None: ...
    def clear_source_route_mode(self, src_side_id: Optional[SideId]) -> None: ...
    def set_route_weight(self, src_side_id: Optional[SideId], dst_side_id: SideId, weight: int) -> None: ...
    def clear_route_weight(self, src_side_id: Optional[SideId], dst_side_id: SideId) -> None: ...
    def set_route_priority(self, src_side_id: Optional[SideId], dst_side_id: SideId, priority: int) -> None: ...
    def clear_route_priority(self, src_side_id: Optional[SideId], dst_side_id: SideId) -> None: ...

    def rx_packet_from_side(self, side_id: SideId, packet: Packet) -> None: ...
    """
        Enqueue a full Packet that arrived on a given side into the relay RX queue.

        Parameters
        ----------
        side_id:
            Side id previously returned by :meth:`add_side_packed` or :meth:`add_side_packet`.
        packet:
            A :class:`Packet` instance.
        """
    def rx_packed_from_side(self, side_id: SideId, data: Buffer | bytes | bytearray | memoryview) -> None: ...
    """
        Enqueue packed bytes that arrived on a given side into the relay RX queue.

        Parameters
        ----------
        side_id:
            Side id previously returned by :meth:`add_side_packed`.
        data:
            Packed packet bytes.
        """
    def clear_queues(self) -> None: ...
    def clear_rx_queue(self) -> None: ...
    def clear_tx_queue(self) -> None: ...

    def process_rx_queue(self) -> None: ...
    def process_tx_queue(self) -> None: ...
    def process_all_queues(self) -> None: ...

    def process_rx_queue_with_timeout(self, timeout_ms: int) -> None: ...
    def process_tx_queue_with_timeout(self, timeout_ms: int) -> None: ...
    def process_all_queues_with_timeout(self, timeout_ms: int) -> None: ...
    def periodic(self, timeout_ms: int) -> None: ...
    def announce_discovery(self) -> None: ...
    def poll_discovery(self) -> bool: ...
    def export_topology(self) -> Dict[str, Any]: ...
    def export_runtime_stats(self) -> Dict[str, Any]: ...

# ==============================
# Top-level helpers
# ==============================

def unpack_packet_py(data: Buffer | bytes | bytearray | memoryview) -> Packet: ...
def peek_header_py(data: Buffer | bytes | bytearray | memoryview) -> Dict[str, Any]: ...
def make_packet(
    ty: int,
    sender: str,
    endpoints: Sequence[int],
    timestamp_ms: int,
    payload: Buffer | bytes | bytearray | memoryview,
) -> Packet: ...
def endpoint_exists(endpoint: int) -> bool: ...
def data_type_exists(ty: int) -> bool: ...
def register_endpoint(endpoint: int, name: str, link_local_only: bool = ..., description: str = ...) -> int: ...
def register_data_type(
    ty: int,
    name: str,
    is_static: bool,
    element_count: int,
    message_data_type: int,
    message_class: int,
    endpoints: Sequence[int],
    reliable: int = ...,
    priority: int = ...,
    description: str = ...,
    e2e_encryption: int = ...,
) -> int: ...
def register_schema_json_bytes(data: Buffer | bytes | bytearray | memoryview) -> None: ...
def register_schema_json_file(path: str) -> None: ...
def endpoint_info(endpoint: int) -> Dict[str, Any]: ...
def data_type_info(ty: int) -> Dict[str, Any]: ...
def endpoint_info_by_name(name: str) -> Dict[str, Any]: ...
def data_type_info_by_name(name: str) -> Dict[str, Any]: ...
def remove_endpoint(endpoint: int) -> bool: ...
def remove_endpoint_by_name(name: str) -> bool: ...
def remove_data_type(ty: int) -> bool: ...
def remove_data_type_by_name(name: str) -> bool: ...
