from __future__ import annotations

import time
from typing import Iterable, Sequence

from cosmic_driver import DeviceInfo, I3cTargetInfo


def assert_status(status: int, operation: str, expected: Iterable[int] = (0,)) -> None:
    expected_codes = tuple(expected)
    expected_text = ", ".join(f"0x{code:04X}" for code in expected_codes)
    assert status in expected_codes, f"{operation} failed. STATUS=0x{status:04X}. Expected: {expected_text}"


def print_device_info(info: DeviceInfo) -> None:
    print(f"Manufacturer: {info.manufacturer}")
    print(f"Product name: {info.product_name}")
    print(f"Serial number: {info.serial_number}")
    print(f"FW version: {info.fw_version}")
    print(f"HW version: {info.hw_version}")


def print_payload(label: str, payload: Sequence[int]) -> None:
    print(f"{label} [{' '.join(str(byte) for byte in payload)}]")


def print_hex_payload(label: str, payload: Sequence[int]) -> None:
    print(f"{label} [{' '.join(f'0x{byte:02X}' for byte in payload)}]")


def print_target_device_table(targets: Sequence[I3cTargetInfo]) -> None:
    for target in targets:
        print(f"\tStatic address: {target.static_address}")
        print(f"\tDynamic address: {target.dynamic_address}")
        print(f"\tPID: {' '.join(str(byte) for byte in target.pid)}")
        print(f"\tBCR: {target.bcr.byte}")
        print(f"\tDCR: {target.dcr}")
        print(f"\tMWL: {target.mwl}")
        print(f"\tMRL: {target.mrl}")
        print(f"\tMax IBI payload length: {target.max_ibi_payload_length}")
        print("\tTarget configuration:")
        print(f"\t\tTarget type: {'I2C' if target.configuration.target_type else 'I3C'}")
        print(f"\t\tInterrupt request: {'ACCEPT IBI' if target.configuration.ibi_request else 'REJECT IBI'}")
        print(f"\t\tController role request: {'ACCEPT CR' if target.configuration.cr_request else 'REJECT CR'}")
        print(f"\t\tSETDASA: {'USE SETDASA' if target.configuration.daa_use_setdasa else 'DO NOT USE SETDASA'}")
        print(f"\t\tSETAASA: {'USE SETAASA' if target.configuration.daa_use_setaasa else 'DO NOT USE SETAASA'}")
        print(f"\t\tENTDAA: {'USE ENTDAA' if target.configuration.daa_use_entdaa else 'DO NOT USE ENTDAA'}")
        print(f"\t\tIBI timestamp: {'ENABLE' if target.configuration.ibi_timestamp_enable else 'DISABLE'}")
        print(
            "\t\tPending read capability: "
            f"{'ENABLE' if target.configuration.pending_read_capability else 'DISABLE'}"
        )
        print("\t-----------------------------------------------")


def wait_until(predicate, timeout_s: float, poll_interval_s: float = 0.05) -> bool:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        if predicate():
            return True
        time.sleep(poll_interval_s)
    return False
