import pytest

from cal_tools.calcat_interface2 import (
    CalibrationData,
    AGIPDConditions,
    DSSCConditions,
    LPDConditions,
    SingleConstantVersion,
)


@pytest.mark.requires_gpfs
def test_AGIPD_CalibrationData_metadata():
    """Test CalibrationData with AGIPD condition"""
    cond = AGIPDConditions(
        # From: https://in.xfel.eu/calibration/calibration_constants/5754#condition
        sensor_bias_voltage=300,  # V
        memory_cells=352,
        acquisition_rate=2.2,  # MHz
        gain_mode=0,
        gain_setting=1,
        integration_time=12,
        source_energy=9.2,
    )
    agipd_cd = CalibrationData.from_condition(
        cond,
        "MID_DET_AGIPD1M-1",
        event_at="2022-09-01 13:26:48.00",
        calibrations=["Offset", "SlopesFF"],
    )
    assert "Offset" in agipd_cd
    assert set(agipd_cd["Offset"].constants) == {f"AGIPD{m:02}" for m in range(16)}
    assert isinstance(agipd_cd["Offset"].constants["AGIPD00"], SingleConstantVersion)


@pytest.mark.requires_gpfs
def test_AGIPD_CalibrationData_metadata_SPB():
    """Test CalibrationData with AGIPD condition"""
    cond = AGIPDConditions(
        sensor_bias_voltage=300,
        memory_cells=352,
        acquisition_rate=1.1,
        integration_time=12,
        source_energy=9.2,
        gain_mode=0,
        gain_setting=0,
    )
    agipd_cd = CalibrationData.from_condition(
        cond,
        "SPB_DET_AGIPD1M-1",
        event_at="2020-01-07 13:26:48.00",
    )
    assert "Offset" in agipd_cd
    assert set(agipd_cd["Offset"].constants) == {f"AGIPD{m:02}" for m in range(16)}
    assert agipd_cd["Offset"].module_nums == list(range(16))
    assert agipd_cd["Offset"].qm_names == [
        f"Q{(m // 4) + 1}M{(m % 4) + 1}" for m in range(16)
    ]
    assert isinstance(agipd_cd["Offset"].constants["AGIPD00"], SingleConstantVersion)


@pytest.mark.requires_gpfs
def test_DSSC_modules_missing():
    dssc_cd = CalibrationData.from_condition(
        DSSCConditions(sensor_bias_voltage=100, memory_cells=600),
        "SQS_DET_DSSC1M-1",
        event_at="2023-11-29 00:00:00",
    )
    # DSSC was used with only 3 quadrants at this point
    modnos = list(range(4)) + list(range(8, 16))
    assert dssc_cd.aggregator_names == [f"DSSC{m:02}" for m in modnos]
    assert dssc_cd.module_nums == modnos
    assert dssc_cd.qm_names == [f"Q{(m // 4) + 1}M{(m % 4) + 1}" for m in modnos]


@pytest.mark.requires_gpfs
def test_LPD_constant_missing():
    lpd_cd = CalibrationData.from_condition(
        LPDConditions(memory_cells=200, sensor_bias_voltage=250),
        "FXE_DET_LPD1M-1",
        event_at="2022-05-22T02:00:00",
    )
    # Constants are missing for 1 module (LPD05), but it was still included in
    # the PDUs for the detector, so it should still appear in the lists.
    assert lpd_cd.aggregator_names == [f"LPD{m:02}" for m in range(16)]
    assert lpd_cd.module_nums == list(range(16))
    assert lpd_cd.qm_names == [f"Q{(m // 4) + 1}M{(m % 4) + 1}" for m in range(16)]

    # When we look at a specific constant, module LPD05 is missing
    assert lpd_cd["Offset"].module_nums == list(range(0, 5)) + list(range(6, 16))


@pytest.mark.xfail
@pytest.mark.requires_gpfs
def test_AGIPD_CalibrationData_report():
    """Test CalibrationData with data from report"""
    # Report ID: https://in.xfel.eu/calibration/reports/3757
    agipd_cd = CalibrationData.from_report(3757)
    assert set(agipd_cd) == {"Offset", "Noise", "ThresholdsDark", "BadPixelsDark"}
    assert agipd_cd.aggregator_names == [f"AGIPD{n:02}" for n in range(16)]
    assert isinstance(agipd_cd["Offset"].constants["AGIPD00"], SingleConstantVersion)