from __future__ import annotations

import threading
import sys
from pathlib import Path


ROOT = next(parent for parent in Path(__file__).resolve().parents if (parent / "cosmic_driver").is_dir())
sys.path.insert(0, str(ROOT))

from cosmic_driver import CosmicPySDK, FW_INTERFACE_ALREADY_INITIALIZED, NotificationType, SUCCESS, UartBaudRate, UartDataSize, UartHwHandshake, UartParity, UartStopBit
from example_helpers import print_device_info, assert_status


def main() -> None:
    rx_condition = threading.Condition()
    rx_notifications = {"count": 0}

    def wait_for_rx(expected_count: int, stage: str) -> None:
        with rx_condition:
            received = rx_condition.wait_for(lambda: rx_notifications["count"] >= expected_count, timeout=2.0)
        if not received:
            raise RuntimeError(f"Timeout while waiting for UART loopback notification at {stage}.")

    with CosmicPySDK(timeout_ms=2000) as device:
        def on_notification(notification) -> None:
            if notification.type != NotificationType.NOTIF_UART or notification.uart_rx is None:
                return
            print("[UART Notification] " + "".join(chr(byte) for byte in notification.uart_rx.data))
            with rx_condition:
                rx_notifications["count"] += 1
                rx_condition.notify_all()

        device.on_notification(on_notification)

        if not device.open():
            raise RuntimeError("Failed to connect to a Binho device.")

        status, info = device.get_device_info()
        assert_status(status, "get_device_info")
        assert info is not None
        print_device_info(info)

        status, _ = device.uart_init(
            UartBaudRate.UART_BAUD_115200,
            UartHwHandshake.UART_HW_HANDSHAKE_DIS,
            UartParity.UART_PARITY_NONE,
            UartDataSize.UART_DATA_SIZE_8,
            UartStopBit.UART_STOP_BIT_1,
        )
        assert_status(status, "uart_init", (SUCCESS, FW_INTERFACE_ALREADY_INITIALIZED))

        message = [ord(char) for char in "Hello, world!"]
        status, _ = device.uart_send_message(message)
        assert_status(status, "uart_send_message(115200)")
        wait_for_rx(1, "115200 send")

        status, _ = device.uart_set_parameters(
            UartBaudRate.UART_BAUD_9600,
            UartHwHandshake.UART_HW_HANDSHAKE_DIS,
            UartParity.UART_PARITY_NONE,
            UartDataSize.UART_DATA_SIZE_8,
            UartStopBit.UART_STOP_BIT_1,
        )
        assert_status(status, "uart_set_parameters")

        status, _ = device.uart_send_message(message)
        assert_status(status, "uart_send_message(9600)")
        wait_for_rx(2, "9600 send")


if __name__ == "__main__":
    main()
