import os.path
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param


class AudioTestParam:
    """
    Class `AudioTestParam` describes requirement parameters for audio test:
    - Set and get `sample_rate`. Describes expected sampling rate of audio signal.
    - Set and get `audio_frequency`. Describes expected audible (sine) frequency as Hz.
    - Set and get `frequency_tolerance`. Describes allowed deviation from expected frequency as Hz.
    - Set and get `audio_glitches_allowed`. Describes number of audio glitches allowed per test.
    - Set and get `save_conditions`. Describes tested audio save conditions.
    - Set and get `storage_folder`. Describes location where the captured audio is to be saved.
    """
    __SAVE_CONDITION = {"None": 0,
                        'Failed': 1,
                        'All': 2}

    def __init__(self, json_obj):
        self.__sample_rate = Param(json_obj["TSI_EXPECTED_SAMPLE_RATE"])
        self.__audio_frequency = Param(json_obj["TSI_EXPECTED_AUDIO_FREQUENCY"])
        self.__frequency_tolerance = Param(json_obj["TSI_AUDIO_FREQUENCY_TOLERANCE"])
        self.__glitch_detect_threshold = Param(json_obj["TSI_AUDIO_GLITCH_DETECT_TRESHOLD"])
        self.__audio_glitches_allowed = Param(json_obj["TSI_AUDIO_GLITCHES_ALLOWED"])
        self.__save_conditions = Param(json_obj["TSI_AUDIO_TEST_SAVE_CONDITIONS"])
        self.__storage_folder = Param(json_obj["TSI_AUDIO_TEST_STORAGE_FOLDER"])

    @property
    def sample_rate(self) -> int:
        """
        Set and get sampling rate of audio signal.

        Returns:
            object of int type
        """
        return self.__sample_rate.default_value

    @sample_rate.setter
    def sample_rate(self, sample_rate: int):
        if not(self.__sample_rate.min_value < sample_rate < self.__sample_rate.max_value):
            raise ValueError(f"Sample rate cannot be less than {self.__sample_rate.min_value} and more than "
                             f"{self.__sample_rate.max_value}.")
        self.__sample_rate.default_value = sample_rate

    @property
    def audio_frequency(self) -> int:
        """
        Set and get audible (sine) frequency as Hz.

        Returns:
            object of int type
        """
        return self.__audio_frequency.default_value

    @audio_frequency.setter
    def audio_frequency(self, audio_frequency: int):
        if not(self.__audio_frequency.min_value < audio_frequency < self.__audio_frequency.max_value):
            raise ValueError(f"Audio frequency cannot be less than {self.__audio_frequency.min_value} and more than "
                             f"{self.__audio_frequency.max_value}.")
        self.__audio_frequency.default_value = audio_frequency

    @property
    def frequency_tolerance(self) -> int:
        """
        Set and get allowed deviation from expected frequency as Hz.

        Returns:
            object of int type
        """
        return self.__frequency_tolerance.default_value

    @frequency_tolerance.setter
    def frequency_tolerance(self, frequency_tolerance: int):
        if not(self.__frequency_tolerance.min_value < frequency_tolerance < self.__frequency_tolerance.max_value):
            raise ValueError(f"Frequency tolerance cannot be less than {self.__frequency_tolerance.min_value} "
                             f"and more than {self.__frequency_tolerance.max_value}.")
        self.__frequency_tolerance.default_value = frequency_tolerance

    @property
    def audio_glitches_allowed(self) -> int:
        """
        Set and get number of audio glitches allowed per test.

        Returns:
            object of int type
        """
        return self.__audio_glitches_allowed.default_value

    @audio_glitches_allowed.setter
    def audio_glitches_allowed(self, audio_glitches_allowed: int):
        if not(self.__audio_glitches_allowed.min_value < audio_glitches_allowed < self.__audio_glitches_allowed.max_value):
            raise ValueError(f"Audio glitches allowed cannot be less than {self.__audio_glitches_allowed.min_value} "
                             f"and more than {self.__audio_glitches_allowed.max_value}.")
        self.__audio_glitches_allowed.default_value = audio_glitches_allowed

    @property
    def glitch_detect_threshold(self) -> int:
        """
        Set and get number of audio glitches allowed per test.

        Returns:
            object of int type
        """
        return self.__glitch_detect_threshold.default_value

    @glitch_detect_threshold.setter
    def glitch_detect_threshold(self, glitch_detect_threshold: int):
        if not (
                self.__glitch_detect_threshold.min_value < glitch_detect_threshold < self.__glitch_detect_threshold.max_value):
            raise ValueError(f"Glitch detect threshold cannot be less than {self.__glitch_detect_threshold.min_value} "
                             f"and more than {self.__glitch_detect_threshold.max_value}.")
        self.__glitch_detect_threshold.default_value = glitch_detect_threshold

    @property
    def save_conditions(self) -> str:
        """
        Set and get tested audio save conditions.

        Returns:
            object of str type
        """
        return self.__save_conditions.default_value

    @save_conditions.setter
    def save_conditions(self, save_conditions: str = 'None'):
        if self.__SAVE_CONDITION.get(save_conditions) is None:
            available_variants = '\n'.join(self.__SAVE_CONDITION.keys())
            raise ValueError(f"Incorrect input parameter {save_conditions}.\n"
                             f"Available variants: {available_variants}")
        self.__save_conditions.default_value = self.__SAVE_CONDITION.get(save_conditions)

    @property
    def storage_folder(self) -> str:
        """
        Set and get location where the captured audio is to be saved.

        Returns:
            object of str type
        """
        return self.__storage_folder.default_value

    @storage_folder.setter
    def storage_folder(self, storage_folder: str):
        if self.__save_conditions.default_value != 0 and not os.path.exists(storage_folder):
            raise ValueError('Incorrect input path. Path is not exist.')
        self.__storage_folder.default_value = storage_folder
