# flake8: noqa
import os
import pprint

import pytest

import adijif
import adijif.converters
import adijif.converters.ad9084_util

here = os.path.dirname(os.path.abspath(__file__))
profile_json = os.path.join(
    here, "apollo_profiles", "ad9084_profiles", "id00_stock_mode.json"
)
summary_json = os.path.join(
    here, "apollo_profiles", "ad9084_profiles", "id00_stock_mode.summary"
)


ref = {
    "common_lane_rate_Hz": 20625000000,
    "core_clock_Hz": None,
    "datapath": {
        "cddc_decimation": 4,
        "cduc_interpolation": 4,
        "fddc_decimation": 2,
        "fduc_interpolation": 2,
    },
    "device_clock_Hz": 20000000000,
    "id": "id00_stock_mode",
    "is_8t8r": False,
    "jesd_settings": {
        "jrx": {
            "F": 1,
            "HD": True,
            # "K": 256,
            "L": 8,
            "M": 4,
            # "N": 16,
            "Np": 16,
            "S": 1,
        },
        "jtx": {
            "F": 1,
            "HD": True,
            # "K": 256,
            "L": 8,
            "M": 4,
            # "N": 16,
            "Np": 16,
            "S": 1,
        },
    },
    "profile_name": "id00_stock_mode",
    "rx_jesd_mode": 47,
    "tx_jesd_mode": 47,
}


def test_config_parser():

    settings = adijif.converters.ad9084_util.parse_json_config(profile_json)

    print("Settings:")
    pprint.pprint(settings)

    assert settings is not None

    # Verify the settings match the reference
    for key in ref:
        if isinstance(ref[key], dict):
            assert settings[key] == ref[key]
        else:
            assert settings[key] == ref[key], f"Mismatch for key: {key}"


def test_ad9084_separate_model_update():

    settings = adijif.converters.ad9084_util.parse_json_config(profile_json)

    print("Settings:")
    pprint.pprint(settings)

    assert settings is not None

    # Apply the settings to the AD9084 RX
    vcxo = 125000000
    clock = "hmc7044"
    sys = adijif.system("ad9084_rx", clock, "xilinx", vcxo, solver="CPLEX")

    adijif.converters.ad9084_util.apply_settings(sys.converter, settings)

    # Verify the settings were applied correctly
    # converter_rate / (cddc_dec * fddc_dec)
    assert sys.converter.converter_clock == settings["device_clock_Hz"]
    assert sys.converter.sample_clock == settings["device_clock_Hz"] / (
        settings["datapath"]["cddc_decimation"]
        * settings["datapath"]["fddc_decimation"]
    )
    # Check the JESD settings
    keys = settings["jesd_settings"]["jrx"].keys()
    for key in keys:
        assert (
            getattr(sys.converter, key) == settings["jesd_settings"]["jtx"][key]
        ), f"Mismatch for key: {key}"


def test_ad9084_model_update():

    settings = adijif.converters.ad9084_util.parse_json_config(profile_json)

    print("Settings:")
    pprint.pprint(settings)

    assert settings is not None

    # Apply the settings to the AD9084 RX
    vcxo = 125000000
    clock = "hmc7044"
    sys = adijif.system("ad9084_rx", clock, "xilinx", vcxo, solver="CPLEX")

    sys.converter.apply_profile_settings(profile_json)

    # Verify the settings were applied correctly
    # converter_rate / (cddc_dec * fddc_dec)
    assert sys.converter.converter_clock == settings["device_clock_Hz"]
    assert sys.converter.sample_clock == settings["device_clock_Hz"] / (
        settings["datapath"]["cddc_decimation"]
        * settings["datapath"]["fddc_decimation"]
    )
    # Check the JESD settings
    keys = settings["jesd_settings"]["jrx"].keys()
    for key in keys:
        assert (
            getattr(sys.converter, key) == settings["jesd_settings"]["jtx"][key]
        ), f"Mismatch for key: {key}"


def test_ad9088_smoke():

    vcxo = int(125e6)
    cddc_dec = 4
    fddc_dec = 4
    converter_rate = int(8e9)

    sys = adijif.system("ad9088_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    sys.fpga.setup_by_dev_kit_name("vcu118")
    sys.converter.sample_clock = converter_rate / (cddc_dec * fddc_dec)
    sys.converter.datapath.cddc_decimations = [cddc_dec] * 8
    sys.converter.datapath.fddc_decimations = [fddc_dec] * 16
    sys.converter.datapath.fddc_enabled = [True] * 16

    sys.converter.clocking_option = "direct"
    sys.add_pll_inline("adf4382", vcxo, sys.converter)
    sys.add_pll_sysref("adf4030", vcxo, sys.converter, sys.fpga)

    sys.clock.minimize_feedback_dividers = False

    mode_rx = adijif.utils.get_jesd_mode_from_params(
        sys.converter, M=8, L=8, S=1, Np=16, jesd_class="jesd204c"
    )

    sys.solve()


def test_ad9084_datapath_config():
    """Test AD9084 datapath configuration."""
    vcxo = 125000000
    clock = "hmc7044"
    sys = adijif.system("ad9084_rx", clock, "xilinx", vcxo, solver="CPLEX")

    # Configure datapath
    sys.converter.datapath.cddc_decimations = [4, 4, 4, 4]
    sys.converter.datapath.fddc_decimations = [2, 2, 2, 2, 2, 2, 2, 2]
    sys.converter.datapath.fddc_enabled = [True] * 8

    assert sys.converter.datapath.cddc_decimations == [4, 4, 4, 4]
    assert sys.converter.datapath.fddc_decimations == [2, 2, 2, 2, 2, 2, 2, 2]


def test_ad9088_datapath_config():
    """Test AD9088 datapath configuration."""
    vcxo = 125000000
    sys = adijif.system("ad9088_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    # Configure datapath
    sys.converter.datapath.cddc_decimations = [4] * 8
    sys.converter.datapath.fddc_decimations = [4] * 16
    sys.converter.datapath.fddc_enabled = [True] * 16

    assert len(sys.converter.datapath.cddc_decimations) == 8
    assert len(sys.converter.datapath.fddc_decimations) == 16


def test_ad9084_clocking_options():
    """Test AD9084 with different clocking options."""
    vcxo = 125000000
    sys = adijif.system("ad9084_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    # Test direct clocking (available for AD9084)
    sys.converter.clocking_option = "direct"
    assert sys.converter.clocking_option == "direct"


def test_ad9084_datapath_get_config():
    """Test AD9084 datapath get_config method."""
    vcxo = 125000000
    sys = adijif.system("ad9084_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    sys.converter.datapath.cddc_decimations = [4, 4, 4, 4]
    sys.converter.datapath.fddc_decimations = [2, 2, 2, 2, 2, 2, 2, 2]
    sys.converter.datapath.fddc_enabled = [True] * 8

    config = sys.converter.datapath.get_config()
    assert config is not None
    assert "cddc" in config
    assert "decimations" in config["cddc"]
    assert "fddc" in config
    assert "decimations" in config["fddc"]


def test_ad9088_datapath_get_config():
    """Test AD9088 datapath get_config method."""
    vcxo = 125000000
    sys = adijif.system("ad9088_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    sys.converter.datapath.cddc_decimations = [4] * 8
    sys.converter.datapath.fddc_decimations = [4] * 16
    sys.converter.datapath.fddc_enabled = [True] * 16

    config = sys.converter.datapath.get_config()
    assert config is not None


def test_ad9084_util_get_jesd_settings():
    """Test AD9084 util get_jesd_settings function."""
    import adijif.converters.ad9084_util as util

    # Test parsing settings
    settings = util.parse_json_config(profile_json)

    # Should have JESD settings
    assert "jesd_settings" in settings
    assert "jrx" in settings["jesd_settings"] or "jtx" in settings["jesd_settings"]


def test_ad9084_apply_settings_function():
    """Test AD9084 apply_settings utility function."""
    import adijif.converters.ad9084_util as util

    vcxo = 125000000
    sys = adijif.system("ad9084_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    settings = util.parse_json_config(profile_json)

    # Apply settings
    util.apply_settings(sys.converter, settings)

    # Verify settings were applied
    assert sys.converter.sample_clock > 0


def test_ad9084_converter_properties():
    """Test AD9084 converter properties."""
    vcxo = 125000000
    sys = adijif.system("ad9084_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    # Test various properties
    assert sys.converter.name == "AD9084_RX"
    assert hasattr(sys.converter, "datapath")
    assert hasattr(sys.converter, "clocking_option")


def test_ad9088_converter_properties():
    """Test AD9088 converter properties."""
    vcxo = 125000000
    sys = adijif.system("ad9088_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    # Test various properties
    assert sys.converter.name == "AD9088_RX"
    assert hasattr(sys.converter, "datapath")


def test_ad9084_sample_clock_setter():
    """Test AD9084 sample clock setter."""
    vcxo = 125000000
    sys = adijif.system("ad9084_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    # Set sample clock
    sys.converter.sample_clock = 2e9
    assert sys.converter.sample_clock == 2e9


def test_ad9088_sample_clock_setter():
    """Test AD9088 sample clock setter."""
    vcxo = 125000000
    sys = adijif.system("ad9088_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX")

    # Set sample clock
    sys.converter.sample_clock = 2e9
    assert sys.converter.sample_clock == 2e9
