"""Tests focused on validating AssonantDataRetriever methods"""

import json
import os

import pytest

from assonant.data_retriever import AssonantDataRetriever
from assonant.data_retriever.exceptions import AssonantDataRetrieverError
from assonant.naming_standards import AcquisitionType, BeamlineName


def assert_retrieved_pv_data_structure(retrieved_pv_data):
    """
    Helper function to validate the structure of the retrieved PV data.

    Expected Structure:
        - The retrieved PV data must be a dictionary where:
            - Keys are strings representing PV names.
            - Values must always be returned inside lists as treatment must be done on highler layers.
    """
    assert isinstance(retrieved_pv_data, dict)

    for key, value in retrieved_pv_data.items():
        assert isinstance(key, str)
        # Data retriever must always return info within a list, treatment must be done on higher layers.
        assert isinstance(value, list)


@pytest.fixture(scope="session")
def example_bluesky_data_retriever(example_bluesky_all_streams_acquisition_file_path) -> AssonantDataRetriever:
    """
    Provides a functional AssonantMetadataRetriever for the example_metadata.csv.
    """
    return AssonantDataRetriever(data_source=example_bluesky_all_streams_acquisition_file_path)


def test_data_retriever_invalid_file_format():
    """
    Validate that AssonantDataRetriever constructor correctly raises exception
    if path to a file of an unsupported file format is passed during object construction.

    Expected Behavior:
        - AssonantDataRetriever must raise an DataRetrieverFactoryError if an filepath for unsupported
        file format is passed.
    """
    with pytest.raises(AssonantDataRetrieverError):
        _ = AssonantDataRetriever(data_source="UNSUPPORTED_FILE_FORMAT")


@pytest.mark.parametrize("acquisition_type", [acq_type for acq_type in AcquisitionType])
def test_get_pv_data_by_acquisition_type_returned_structure(example_bluesky_data_retriever, acquisition_type):
    """
    Validate that AssonantDataRetriever get_pv_data_by_acquisition_type() method correctly return expected
    value when acquisition type does exist.

    Expected Behavior:
        - AssonantDataRetriever be able to return a dictionary containing retrieved PV data
        from the acquisition type.
        - The dictionary structure must follow exactly the one define at the
        IAssonantDataRetriever interface.
    """
    retrieved_pv_data = example_bluesky_data_retriever.get_pv_data_by_acquisition_type(acquisition_type)

    assert_retrieved_pv_data_structure(retrieved_pv_data)


@pytest.mark.parametrize("beamline_name", [beamline_name for beamline_name in BeamlineName])
@pytest.mark.parametrize("acquisition_type", [acq_type for acq_type in AcquisitionType])
def test_get_pv_data_by_acquisition_type_returned_structure_over_real_example_data(
    beamline_name, acquisition_type, real_bluesky_data_test_cases_dir_path_map
):
    """
    Validate that AssonantDataRetriever get_pv_data_by_acquisition_type() method correctly return expected
    structure over real example data.

    Expected Behavior:
        - AssonantDataRetriever be able to return a dictionary containing retrieved PV data
        for each acquisition Type for all real data test cases that exist for each beamline.
        - The dictionary structure must follow exactly the one define at the
        IAssonantDataRetriever interface.
    """
    if beamline_name.value not in real_bluesky_data_test_cases_dir_path_map.keys():
        pytest.skip(reason=f"There is no test case with real data for {beamline_name} beamline yet!")
    else:

        for i in range(0, len(real_bluesky_data_test_cases_dir_path_map[beamline_name.value])):
            # Execute test for each test case dir that exist for that beamline
            test_case_dir = real_bluesky_data_test_cases_dir_path_map[beamline_name.value][i]

            for test_case_file in os.scandir(test_case_dir):
                if test_case_file.is_file() and test_case_file.name.endswith(".json"):

                    with open(test_case_file) as f:
                        test_case_bluesky_docs_list = json.load(f)

                data_retriever = AssonantDataRetriever(data_source=test_case_bluesky_docs_list)

                retrieved_pv_data = data_retriever.get_pv_data_by_acquisition_type(acquisition_type)
                assert_retrieved_pv_data_structure(retrieved_pv_data)
