"""Tests for neng_scpi_tools — verifies the shared package is importable and self-consistent."""

from __future__ import annotations


def test_package_version():
    """Package exposes __version__."""
    import neng_scpi_tools  # type: ignore

    assert hasattr(neng_scpi_tools, "__version__")
    assert isinstance(neng_scpi_tools.__version__, str)
    parts = neng_scpi_tools.__version__.split(".")
    assert len(parts) == 3, f"Expected semver, got {neng_scpi_tools.__version__}"


def test_import_scpi_serial():
    """SCPISerial is importable from the shared package."""
    from neng_scpi_tools.myserial.scpi_serial import SCPISerial  # type: ignore

    assert callable(SCPISerial)


def test_import_scpi_serial_via_init():
    """SCPISerial is re-exported from myserial.__init__."""
    from neng_scpi_tools.myserial import SCPISerial  # type: ignore

    assert callable(SCPISerial)


def test_import_scpi_universal():
    """SCPIUniversal is importable from the shared package."""
    from neng_scpi_tools.myserial.scpi_universal import SCPIUniversal  # type: ignore

    assert callable(SCPIUniversal)


def test_import_tcp_socket():
    """TCPSocket helper is importable."""
    from neng_scpi_tools.myserial.scpi_universal import TCPSocket  # type: ignore

    assert callable(TCPSocket)


def test_import_connection_panel():
    """ConnectionPanel is importable from the shared package."""
    from neng_scpi_tools.connection_panel import ConnectionPanel  # type: ignore

    assert callable(ConnectionPanel)


def test_import_scan_serial_ports():
    """scan_serial_ports helper is importable."""
    from neng_scpi_tools.connection_panel import scan_serial_ports  # type: ignore

    assert callable(scan_serial_ports)
    ports = scan_serial_ports()
    assert isinstance(ports, list)
    assert "Auto-detect" in ports


def test_import_device_in_use_error():
    """DeviceInUseError exception class is importable."""
    from neng_scpi_tools.myserial.scpi_serial import DeviceInUseError  # type: ignore

    assert issubclass(DeviceInUseError, RuntimeError)


def test_import_port_lock():
    """PortLock class is importable."""
    from neng_scpi_tools.myserial.scpi_serial import PortLock  # type: ignore

    assert callable(PortLock)


def test_scpi_serial_class_has_key_methods():
    """SCPISerial exposes the expected public API."""
    from neng_scpi_tools.myserial.scpi_serial import SCPISerial  # type: ignore

    for method_name in (
        "connect",
        "close",
        "write",
        "read",
        "query",
        "query_float",
        "query_int",
        "query_bool",
        "wait_opc",
        "list_ports",
        "find_neng_port",
        "get_useful_ports",
        "get_identification",
    ):
        assert hasattr(SCPISerial, method_name), f"Missing method: {method_name}"


def test_scpi_universal_class_has_key_methods():
    """SCPIUniversal exposes the expected public API."""
    from neng_scpi_tools.myserial.scpi_universal import SCPIUniversal  # type: ignore

    for method_name in ("connect", "close", "write", "query", "query_binary"):
        assert hasattr(SCPIUniversal, method_name), f"Missing method: {method_name}"


def test_connection_panel_is_ttk_widget():
    """ConnectionPanel subclasses ttk.LabelFrame."""
    from tkinter import ttk

    from neng_scpi_tools.connection_panel import ConnectionPanel  # type: ignore

    assert issubclass(ConnectionPanel, ttk.LabelFrame)


def test_no_relative_imports_to_old_locations():
    """Ensure the shared package does NOT contain stale relative imports
    pointing to the old subproject-local paths (e.g. '.tools.myserial')."""
    import inspect

    from neng_scpi_tools import connection_panel as cp_mod  # type: ignore

    source = inspect.getsource(cp_mod)
    assert "from .tools.myserial" not in source, (
        "connection_panel.py still contains 'from .tools.myserial' — "
        "should use 'from neng_scpi_tools.myserial'"
    )


# ===================================================================
# scpi_client tests
# ===================================================================


def test_import_scpi_client():
    """scpi_client module is importable."""
    from neng_scpi_tools import scpi_client  # type: ignore

    assert hasattr(scpi_client, "main")
    assert hasattr(scpi_client, "format_response")


def test_scpi_client_format_response():
    """format_response is callable and handles basic input."""
    from neng_scpi_tools.scpi_client import format_response  # type: ignore

    # non-pretty mode returns raw response
    assert format_response("*IDN?", "Hello", pretty=False) == "Hello"

    # empty response returns empty
    assert format_response("*IDN?", "", pretty=True) == ""


def test_scpi_client_main_callable():
    """main() entry point is callable."""
    from neng_scpi_tools.scpi_client import main  # type: ignore

    assert callable(main)


def test_scpi_client_has_key_functions():
    """scpi_client exposes the expected public functions."""
    from neng_scpi_tools import scpi_client  # type: ignore

    for name in (
        "format_response",
        "main",
        "interactive_mode",
        "send_scpi_command",
        "print_help",
        "find_neng_ports",
        "parse_wifi_address",
        "TCPSocket",
    ):
        assert hasattr(scpi_client, name), f"Missing: {name}"


def test_scpi_client_no_relative_imports():
    """scpi_client must not use relative imports to temp_logger."""
    import inspect

    from neng_scpi_tools import scpi_client  # type: ignore

    source = inspect.getsource(scpi_client)
    assert "from .device_scanner" not in source, (
        "scpi_client.py still uses 'from .device_scanner' — "
        "should use importlib for pluggable device_scanner"
    )
    assert "from . import __version__" not in source, (
        "scpi_client.py still uses 'from . import __version__' — "
        "should use 'from neng_scpi_tools import __version__'"
    )


def test_scpi_client_direct_import():
    """scpi_client is importable directly from neng_scpi_tools."""
    from neng_scpi_tools.scpi_client import format_response, main  # type: ignore

    assert callable(format_response)
    assert callable(main)
