"""Модуль тестов вкладки 'Резервное копирование'.

Содержит тесты для проверки корректности отображения
и функциональности элементов вкладки настройки времени жизни сеансов.
"""

from datetime import datetime, timezone
import os
from pathlib import Path
import pytest
from playwright.sync_api import Page
from pages.login_page import LoginPage
from pages.main_page import MainPage
from pages.backup_settings_tab import BackupSettingsTab


# @pytest.mark.smoke
class TestBackupSettingsTab:
    """Набор тестов для вкладки 'Сеансы/Настройки'.

    Проверяет корректность отображения и функциональность элементов вкладки настройки времени жизни сеансов.

    Тесты покрывают следующие сценарии:
    1. test_backup_settings_tab_content: Тест содержимого вкладки 'Резервное копирование'
    2. test_edit_session_settings: Тест проверки возможности редактирования выбранных полей формы
                                   настройки времени жизни сеансов.
    3. test_edit_session_setting_by_arrow: Тест проверки возможности увеличения/уменьшения значения
                                           выбранного поля формы с помощью стрелочек Вверх/Вниз.
    """


    @pytest.fixture(scope="function", autouse=True)
    def setup(self, browser: Page) -> None:
        """Фикстура для подготовки тестового окружения.

        Выполняет:
        1. Авторизацию в системе
        2. Переход на вкладку 'Резервное копирование' через панель навигации
        """
        # Авторизация в системе
        login_page = LoginPage(browser)
        login_page.do_login()

        # Инициализация главной страницы
        main_page = MainPage(browser)

        # Проверка и взаимодействие с элементами навигации
        main_page.should_be_navigation_panel()
        main_page.click_main_navigation_panel_item("Настройки")
        main_page.click_subpanel_item("Обслуживание и диагностика")
        main_page.click_subpanel_item("Резервное копирование")

    # @pytest.mark.develop
    def test_backup_settings_tab_content(self, browser: Page) -> None:
        """Тест содержимого вкладки 'Резервное копирование'.

        Проверяет:
        1. Наличие и корректность элементов интерфейса
        2. Соответствие содержимого полей формы данным из БД
        """

        # Инициализация страницы сеансов
        backup_settings_tab = BackupSettingsTab(browser)

        # Проверка элементов интерфейса
        backup_settings_tab.check_content()

        # запрос текущих установок настройки 'Инвентаризация/Параметры планировщика'
        current_settings = {}
        cur_settings_response = backup_settings_tab.send_get_api_request("e-cmdb/api/backupcmdb")
        if cur_settings_response.status == 200:
            response_body = backup_settings_tab.get_response_body(cur_settings_response)

            if response_body:
                current_settings = response_body[0].copy()

        # Проверка соответствия для значений настройки 'Инвентаризация/Параметры планировщика'
        inventory_scheduler_settings = backup_settings_tab.get_inventory_scheduler_settings_values()
        inventory_auto_backup = inventory_scheduler_settings["auto_backup"]
        inventory_backup_limitation = inventory_scheduler_settings["backup_limitation"]

        if len(current_settings) != 0 or len(inventory_auto_backup) != 0 or len(inventory_backup_limitation) != 0:
            # запрос дефолтных значений настройки 'Инвентаризация/Параметры планировщика'
            default_settings = {}
            default_settings_response = backup_settings_tab.send_get_api_request("e-cmdb/api/backupcmdb/meta")
            if default_settings_response.status == 200:
                response_body = backup_settings_tab.get_response_body(default_settings_response)

                if response_body:
                    default_settings = response_body["fields"].copy()

            expected = current_settings["auto_backup"] if len(current_settings) != 0 else None
            if expected is None:
                expected = self._get_default_value("auto_backup", default_settings)
            assert inventory_auto_backup == expected,\
                   f"Actual value {inventory_auto_backup} \
                     is not equal expected {expected} for field 'Время создания резервной копии'"

            expected = current_settings["backup_limitation"] if len(current_settings) != 0 else None
            if expected is None:
                expected = self._get_default_value("backup_limitation", default_settings)
            assert inventory_backup_limitation == expected,\
                   f"Actual value {inventory_backup_limitation} \
                    is not equal expected {expected} for field 'Количество резервных копий'"

        # запрос текущих установок настройки 'Потоковые данные'
        current_sd_settings = {}
        cur_settings_response = backup_settings_tab.send_get_api_request("e-cmdb/api/backupstreamingdata")
        if cur_settings_response.status == 200:
            response_body = backup_settings_tab.get_response_body(cur_settings_response)

            if response_body:
                current_sd_settings = response_body[0].copy()

        # Проверка соответствия для значений настройки 'Потоковые данные/Параметры планировщика'
        streaming_data_scheduler_settings = backup_settings_tab.get_streaming_data_scheduler_settings_values()
        sd_auto_backup = streaming_data_scheduler_settings["auto_backup"]
        if len(current_sd_settings) != 0 or len(sd_auto_backup) != 0:
            # запрос дефолтных значений настройки 'Потоковые данные'
            default_sd_settings = {}
            default_settings_response = backup_settings_tab.send_get_api_request("e-cmdb/api/backupstreamingdata/meta")
            if default_settings_response.status == 200:
                response_body = backup_settings_tab.get_response_body(default_settings_response)

                if response_body:
                    default_sd_settings = response_body["fields"].copy()

            expected = current_sd_settings["auto_backup"] if len(current_settings) != 0 else None
            if expected is None:
                expected = self._get_default_value("auto_backup", default_sd_settings)
            assert sd_auto_backup == expected,\
                   f"Actual value {sd_auto_backup} \
                     is not equal expected {expected} for field 'Время создания резервной копии'"

    # @pytest.mark.develop
    def test_backup_settings_tab_check_backup_copies_amount(self, browser: Page) -> None:
        """Тест проверки количества резервных копий."""

        # TO-DO: Тест проверки правильности времени их создания

        # Инициализация страницы сеансов
        backup_settings_tab = BackupSettingsTab(browser)

        # получение текущих установок настройки 'Инвентаризация/Параметры планировщика'
        inventory_scheduler_settings = backup_settings_tab.get_inventory_scheduler_settings_values()
        #inventory_auto_backup = inventory_scheduler_settings["auto_backup"]
        inventory_backup_limitation = int(inventory_scheduler_settings["backup_limitation"])

        # получение списка резервных копий настройки 'Инвентаризация'
        dumps = backup_settings_tab.get_inventory_dumps_list()

        assert inventory_backup_limitation == len(dumps), \
               f"Required to store {inventory_backup_limitation} but {len(dumps)} stores"

    # @pytest.mark.develop
    def test_backup_settings_tab_create_copy(self, browser: Page) -> None:
        """Тест проверки создания резервных копий."""

        # Инициализация страницы сеансов
        backup_settings_tab = BackupSettingsTab(browser)

        # проверка создания резервной копии для блока 'Инвентаризация'
        current_date = datetime.now(timezone.utc)
        current_ts = current_date.timestamp()

        backup_settings_tab.create_inventory_copy()
        backup_settings_tab.wait_for_timeout(3000)

        dumps_cmdb = backup_settings_tab.get_inventory_dumps_list()
        max_ts, _ = self._get_last_dump(dumps_cmdb, "inventory")
        assert max_ts - current_ts < 1000, "New inventory backup copy not found"

        # проверка создания резервной копии для блока 'Потоковые данные'
        current_date = datetime.now(timezone.utc)
        current_ts = current_date.timestamp()

        backup_settings_tab.create_streaming_data_copy()
        backup_settings_tab.wait_for_timeout(3000)

        dumps_streaming_data = backup_settings_tab.get_streaming_data_dumps_list()
        max_ts, _ = self._get_last_dump(dumps_streaming_data, "streaming_data")
        assert max_ts - current_ts < 1000, "New streaming_data backup copy not found"

    # @pytest.mark.develop
    def test_backup_settings_tab_check_backup_buttons(self, browser: Page) -> None:
        """Тест проверки поведения кнопок управления резервными копиями."""

        # Инициализация страницы сеансов
        backup_settings_tab = BackupSettingsTab(browser)

        dumps_cmdb = backup_settings_tab.get_inventory_dumps_list()
        max_ts, last_dump = self._get_last_dump(dumps_cmdb, "inventory")

        backup_settings_tab.select_inventory_dump(last_dump)

        backup_settings_tab.should_be_inventory_download_button()
        is_disabled = backup_settings_tab.check_inventory_restore_copy_button_disabling()
        assert not is_disabled, "Inventory button to restore copy should be enabled"

        backup_settings_tab.clear_inventory_dump_selection()
        backup_settings_tab.should_be_inventory_upload_button()
        is_disabled = backup_settings_tab.check_inventory_restore_copy_button_disabling()
        assert is_disabled, "Inventory button to restore copy should be disabled"

        dumps_streaming_data = backup_settings_tab.get_streaming_data_dumps_list()
        max_ts, last_dump = self._get_last_dump(dumps_streaming_data, "streaming_data")

        backup_settings_tab.select_streaming_data_dump(last_dump)

        backup_settings_tab.should_be_streaming_data_download_button()
        is_disabled = backup_settings_tab.check_streaming_data_restore_copy_button_disabling()
        assert not is_disabled, "Streaming data button to restore copy should be enabled"

        backup_settings_tab.clear_streaming_data_dump_selection()
        backup_settings_tab.should_be_streaming_data_upload_button()
        is_disabled = backup_settings_tab.check_streaming_data_restore_copy_button_disabling()
        assert is_disabled, "Streaming data button to restore copy should be disabled"

    # @pytest.mark.develop
    def test_backup_settings_tab_check_download_copy(self, browser: Page) -> None:
        """Тест проверки возможности загрузки резервной копии."""

        # TO-DO: Тест проверки возможности загрузки резервной копии для потоковых данных

        # Инициализация страницы сеансов
        backup_settings_tab = BackupSettingsTab(browser)

        path_to_download = Path.home() / "Downloads"

        dumps_cmdb = backup_settings_tab.get_inventory_dumps_list()
        max_ts, last_dump = self._get_last_dump(dumps_cmdb, "inventory")

        backup_settings_tab.download_inventory_copy(last_dump, path_to_download)

        downloaded = str(path_to_download) + "/" + last_dump

        assert os.path.exists(downloaded), f"The file '{downloaded}' not found"
        assert os.path.getsize(downloaded) > 0, f"The file '{downloaded}' is empty"

        os.remove(downloaded)

    @pytest.mark.develop
    def test_backup_settings_tab_set_inventory_scheduler_settings(self, browser: Page) -> None:
        """Тест проверки возможности изменения значения настроек 'Инвентаризация/Параметры планировщика'."""

        # Инициализация страницы сеансов
        backup_settings_tab = BackupSettingsTab(browser)

        backup_settings_tab.click_edit_button()

        backup_settings_tab.input_inventory_backup_creation_time("0 0 22 * * 7")

        backup_settings_tab.input_inventory_backups_number("6")
        backup_settings_tab.decrease_inventory_backups_number()
        backup_settings_tab.increase_inventory_backups_number()

        inventory_scheduler_settings = backup_settings_tab.get_inventory_scheduler_settings_values()
        inventory_auto_backup = inventory_scheduler_settings["auto_backup"]
        inventory_backup_limitation = inventory_scheduler_settings["backup_limitation"]
        assert inventory_auto_backup == "0 0 22 * * 7", \
               f"Actual value '{inventory_auto_backup}' \
                 is not equal expected '0 0 22 * * 7' for field 'Время создания резервной копии'"
        assert inventory_backup_limitation == "6", \
               f"Actual value '{inventory_backup_limitation}' \
                is not equal expected '6' for field 'Количество резервных копий'"

        # temporarily until fix 1280
        backup_settings_tab.click_cancel_button()

    # @pytest.mark.develop
    def test_backup_settings_tab_set_streaming_data_settings(self, browser: Page) -> None:
        """Тест проверки возможности изменения значения настроек 'Потоковые данные'."""

        # Инициализация страницы сеансов
        backup_settings_tab = BackupSettingsTab(browser)

        backup_settings_tab.click_edit_button()

        backup_settings_tab.input_audit_time_period("3", "месяц")
        backup_settings_tab.increase_audit_time_period()
        backup_settings_tab.decrease_audit_time_period()

        backup_settings_tab.input_logs_time_period("3", "месяц")
        backup_settings_tab.increase_logs_time_period()
        backup_settings_tab.decrease_logs_time_period()

        backup_settings_tab.input_metrics_time_period("3", "месяц")
        backup_settings_tab.increase_metrics_time_period()
        backup_settings_tab.decrease_metrics_time_period()

        backup_settings_tab.input_syslog_time_period("3", "месяц")
        backup_settings_tab.increase_syslog_time_period()
        backup_settings_tab.decrease_syslog_time_period()

        backup_settings_tab.input_tasks_time_period("3", "месяц")
        backup_settings_tab.increase_tasks_time_period()
        backup_settings_tab.decrease_tasks_time_period()

        backup_settings_tab.input_streaming_data_backup_creation_time("0 0 22 * * 7")

        streaming_data_settings = backup_settings_tab.get_streaming_data_settings_values()
        data_limitation_default = streaming_data_settings["data_limitation_default"]
        assert data_limitation_default == "3", \
            f"Actual value '{data_limitation_default}' is not equal expected '3' for category 'Аудит'"
        interval_limitation_default = streaming_data_settings["interval_limitation_default"]
        assert interval_limitation_default == "месяц", \
            f"Actual value '{interval_limitation_default}' is not equal expected 'месяц' for category 'Аудит'"
        data_limitation_logs = streaming_data_settings["data_limitation_logs"]
        assert data_limitation_logs == "3", \
            f"Actual value '{data_limitation_logs}' is not equal expected '3' for category 'Логи'"
        interval_limitation_logs = streaming_data_settings["interval_limitation_logs"]
        assert interval_limitation_logs == "месяц", \
            f"Actual value '{interval_limitation_logs}' is not equal expected 'месяц' for category 'Логи'"
        data_limitation_metrics = streaming_data_settings["data_limitation_metrics"]
        assert data_limitation_metrics == "3", \
            f"Actual value '{data_limitation_metrics}' is not equal expected '3' for category 'Метрики'"
        interval_limitation_metrics = streaming_data_settings["interval_limitation_metrics"]
        assert interval_limitation_metrics == "месяц", \
            f"Actual value '{interval_limitation_metrics}' is not equal expected 'месяц' for category 'Метрики'"
        data_limitation_syslog = streaming_data_settings["data_limitation_syslog"]
        assert data_limitation_syslog == "3", \
            f"Actual value '{data_limitation_syslog}' is not equal expected '3' for category 'Системный лог'"
        interval_limitation_syslog = streaming_data_settings["interval_limitation_syslog"]
        assert interval_limitation_syslog == "месяц", \
            f"Actual value '{interval_limitation_syslog}' is not equal expected 'месяц' for category 'Системный лог'"
        data_limitation_tasks = streaming_data_settings["data_limitation_tasks"]
        assert data_limitation_tasks == "3", \
            f"Actual value '{data_limitation_tasks}' is not equal expected '3' for category 'Действия'"
        interval_limitation_tasks = streaming_data_settings["interval_limitation_tasks"]
        assert interval_limitation_tasks == "месяц", \
            f"Actual value '{interval_limitation_tasks}' is not equal expected 'месяц' for category 'Действия'"

        streaming_data_scheduler_settings = backup_settings_tab.get_streaming_data_scheduler_settings_values()
        streaming_data_auto_backup = streaming_data_scheduler_settings["auto_backup"]
        assert streaming_data_auto_backup == "0 0 22 * * 7", \
               f"Actual value '{streaming_data_auto_backup}' \
                 is not equal expected '0 0 22 * * 7' for field 'Потоковые данные Время создания резервной копии'"

        # temporarily until fix 1280
        backup_settings_tab.click_cancel_button()

    # Вспомогательные функции
    def _get_default_value(self, setting_name: str, default_settings: dict) -> str| None:
        """ Выбор дефолтного значения из списка по его имени """

        for setting in default_settings:
            if setting["name"] == setting_name:
                return setting["default"]
        return None

    def _get_last_dump(self, dumps_list: list[str],settings_type : str) -> list:
        """ Выбор последнего по времени дампа из списка.
            Возвращает timestamp и имя дампа.
        """

        dumps = {}
        ret_values = []
        for dump in dumps_list:
            if settings_type == "inventory":
                dump_date = dump.replace("dump_cmdb_", "").replace(".dump", "")
                date_object = datetime.strptime(dump_date, "%Y-%m-%d_%H_%M_%S")
            elif settings_type == "streaming_data":
                dump_date = dump.replace("monitoring_backup_", "").replace(".zip", "")
                date_object = datetime.strptime(dump_date, "%Y-%m-%d_%H-%M-%S")
            else:
                assert False, "Unsupported backup setting type"
            ts = date_object.timestamp()
            dumps[ts] = dump
        max_ts = sorted(dumps.keys())[-1]
        ret_values.append(max_ts)
        ret_values.append(dumps[max_ts])
        return ret_values
