"""双光谱仪（UV/VIS + NIR）同时采集测试例程。

用法（在 examples 目录下）：
    python dual_spectrometer_test.py

流程：扫描 -> 同时打开两台设备 -> 分别切换并采集 -> 对比输出 -> 关闭。
两台设备的参数（积分时间、选区等）相互独立。
"""

import ctypes
import sys
import time
from pathlib import Path

from minimal_test import (
    PynectDirectDeviceInfo,
    bind_api,
    decode_char_array,
    find_dll,
    load_library,
)

CAP_INTEGRATION_TIME = 0x00000001
CAP_SPECTRUM_DATA = 0x00000020

REQUIRED_DEVICES = 2
TEST_INTEGRATION_US = 50000


def require(code, what):
    if code != 0:
        raise RuntimeError(f"{what} failed, return code={code}")


def probe_device(sdk, label):
    """对当前选中设备执行完整采集流程并打印结果。"""
    print(f"\n===== {label} =====")

    info = PynectDirectDeviceInfo()
    require(sdk.pynect_direct_get_device_info(ctypes.byref(info)), "get_device_info")
    print(f"  协议     : {decode_char_array(info.protocol_name)}")
    print(f"  型号     : {decode_char_array(info.model)}")
    print(f"  序列号   : {decode_char_array(info.serial_number)}")
    print(f"  硬件版本 : {decode_char_array(info.hardware_version)}")
    caps = info.capabilities

    count = ctypes.c_uint16()
    require(sdk.pynect_direct_get_wavelength_count(ctypes.byref(count)), "get_wavelength_count")
    n = count.value
    print(f"  波长点数 : {n}")
    if n == 0:
        return

    start, end = ctypes.c_double(), ctypes.c_double()
    require(
        sdk.pynect_direct_get_full_wavelength_range(ctypes.byref(start), ctypes.byref(end)),
        "get_full_wavelength_range",
    )
    print(f"  波长范围 : {start.value:.3f} ~ {end.value:.3f} nm")

    wl = (ctypes.c_double * n)()
    require(sdk.pynect_direct_get_full_wavelength_data(wl, n), "get_full_wavelength_data")
    print(f"  波长首尾 : {wl[0]:.3f} ... {wl[-1]:.3f} nm")

    if caps & CAP_INTEGRATION_TIME:
        try:
            require(sdk.pynect_direct_set_integration_time(TEST_INTEGRATION_US),
                    "set_integration_time")
        except RuntimeError as e:
            print(f"  积分时间 : 设置失败，跳过（{e}）")
        else:
            print(f"  积分时间 : 临时设为 {TEST_INTEGRATION_US} us")

    if caps & CAP_SPECTRUM_DATA:
        spec = (ctypes.c_uint16 * n)()
        t0 = time.perf_counter()
        require(sdk.pynect_direct_get_full_spectrum_data(spec, n), "get_full_spectrum_data")
        elapsed = (time.perf_counter() - t0) * 1000
        print(f"  光谱强度 : min={min(spec)} max={max(spec)}  采集耗时={elapsed:.1f} ms")
        mid = n // 2
        print(f"  中间点   : ({wl[mid]:.3f} nm, {spec[mid]})")

    # 指定波段：取设备自身范围的中间 60%，在上位机截取
    span = end.value - start.value
    sel_lo = start.value + span * 0.2
    sel_hi = start.value + span * 0.8
    require(
        sdk.pynect_direct_set_selected_wavelength_range(sel_lo, sel_hi),
        "set_selected_wavelength_range",
    )
    print(f"  选区请求 : {sel_lo:.3f} ~ {sel_hi:.3f} nm（中间 60%）")


def main():
    sdk = load_library(find_dll())
    bind_api(sdk)

    found = sdk.pynect_direct_scan_devices()
    print(f"扫描到 {found} 台设备")
    if found < REQUIRED_DEVICES:
        print(f"需要至少 {REQUIRED_DEVICES} 台设备，当前 {found} 台，退出")
        return 1

    serials = []
    for i in range(found):
        buf = ctypes.create_string_buffer(64)
        code = sdk.pynect_direct_get_chip_serial_by_index(i, buf, len(buf))
        serial = buf.value.decode("utf-8", errors="replace") if code == 0 else "?"
        serials.append(serial)
        print(f"  [{i}] {serial}")

    opened = False
    try:
        # 同时打开两台设备（互不关闭）
        require(sdk.pynect_direct_open_device(0), "open device 0")
        require(sdk.pynect_direct_open_device(1), "open device 1")
        opened = True
        print(f"\n已打开设备数: {sdk.pynect_direct_get_open_device_count()}")

        # 分别采集
        require(sdk.pynect_direct_select_device(0), "select device 0")
        probe_device(sdk, f"设备 0（{serials[0]}）")

        require(sdk.pynect_direct_select_device(1), "select device 1")
        probe_device(sdk, f"设备 1（{serials[1]}）")

        # 再切回设备 0，确认状态独立
        require(sdk.pynect_direct_select_device(0), "reselect device 0")
        count = ctypes.c_uint16()
        sdk.pynect_direct_get_wavelength_count(ctypes.byref(count))
        print(f"\n切回设备 0，点数 = {count.value}（状态独立，未受影响）")

    finally:
        if opened:
            sdk.pynect_direct_close_all_devices()
            print(f"\n已关闭全部设备，剩余: {sdk.pynect_direct_get_open_device_count()}")

    print("\n双光谱仪测试完成。")
    return 0


if __name__ == "__main__":
    sys.exit(main())
