"""Модуль тестов вкладки 'Стойка' в модуле Объекты.

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

import pytest
from playwright.sync_api import Page
from tools.logger import get_logger
from locators.navigation_panel_locators import NavigationPanelLocators
from frames.create_element_frame import CreateElementFrame
from forms.create_rack_form import CreateRackForm, CreateRackData
from makers.edit_rack_maker import EditRackMaker
from pages.location_page import LocationPage
from pages.login_page import LoginPage
from pages.main_page import MainPage
from pages.rack_page import RackPage
from components.alert_component import AlertComponent


logger = get_logger("RACK_MANAGEMENT_TESTS")
logger.setLevel("INFO")


class TestRackManagement:
    """Набор тестов для вкладки 'Стойка' в модуле Объекты.

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

    # Имя тестовой стойки
    RACK_NAME = "Test-Rack-Functionality"

    # Инициализируем атрибуты
    main_page: MainPage = None
    location_page: LocationPage = None
    alert: AlertComponent = None
    create_child_frame: CreateElementFrame = None

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

        Выполняет:
        1. Авторизацию в системе
        2. Переход к локации test-zone
        3. Инициализацию компонентов
        4. Создание стойки если она не существует
        5. Переход к стойке

        Args:
            browser: Экземпляр страницы Playwright для взаимодействия с UI
        """

        # Авторизация в системе
        login_page = LoginPage(browser)
        login_page.do_login()

        # Мы на главной странице
        self.main_page = MainPage(browser)
        self.main_page.should_be_navigation_panel()

        # Переходим к Объектам
        self.main_page.click_main_navigation_panel_item("Объекты")
        self.main_page.wait_for_timeout(1000)
        self.main_page.click_main_navigation_panel_item("test-zone")

        # Создаем экземпляр страницы локации
        self.location_page = LocationPage(browser)

        # Инициализируем компонент алертов (вынесено в атрибуты класса)
        self.alert = AlertComponent(browser)

        # Инициализируем фрейм создания дочернего элемента (вынесено в атрибуты класса)
        self.create_child_frame = CreateElementFrame(browser)

        # Проверяем существование стойки
        if not self._check_rack_existance(browser, self.RACK_NAME):
            logger.info(f"Rack '{self.RACK_NAME}' does not exist. Creating...")

            rack_data = CreateRackData(
                name=self.RACK_NAME,
                usize="42",
                depth="1000"
            )
            self._create_rack(browser, rack_data)
            self.main_page.wait_for_timeout(3000)
        else:
            logger.info(f"Rack '{self.RACK_NAME}' already exists")

        # Переходим к стойке для тестирования
        self.main_page.click_subpanel_item(self.RACK_NAME, parent="test-zone")
        self.main_page.wait_for_timeout(3000)

    @pytest.fixture(scope="class", autouse=True)
    def cleanup_rack(self, browser: Page):
        """Фикстура для очистки созданной стойки после ВСЕХ тестов класса.

        Выполняется один раз после завершения всех тестов класса TestRackTab.
        Удаляет созданную стойку.

        Args:
            browser: Экземпляр страницы Playwright
        """

        # Тесты выполняются здесь
        yield

        logger.debug(f"Cleaning up rack: {self.RACK_NAME}")

        # Переходим на главную страницу и в нужную зону
        login_page = LoginPage(browser)
        login_page.do_login()

        self.main_page = MainPage(browser)
        self.main_page.should_be_navigation_panel()

        # Переходим к Объектам
        self.main_page.click_main_navigation_panel_item("Объекты")
        self.main_page.wait_for_timeout(1000)
        self.main_page.click_main_navigation_panel_item("test-zone")
        self.main_page.wait_for_timeout(1000)

        # Инициализируем компонент алертов для cleanup
        self.alert = AlertComponent(browser)

        # Проверяем существование стойки
        if self._check_rack_existance(browser, self.RACK_NAME):

            # Переходим на страницу стойки
            self.main_page.click_subpanel_item(self.RACK_NAME, parent="test-zone")
            self.main_page.wait_for_timeout(2000)

            # Удаляем стойку
            self._delete_rack(browser, self.RACK_NAME)

            # Дополнительная проверка
            self.main_page.click_subpanel_item("test-zone")
            self.main_page.wait_for_timeout(1000)

    def _check_rack_existance(self, browser: Page, rack_name: str) -> bool:
        """Проверяет существование стойки.

        Args:
            browser: Страница Playwright
            rack_name: Имя стойки для проверки

        Returns:
            bool: True если стойка существует, False в противном случае
        """

        logger.debug(f"Checking existence of rack with name '{rack_name}'")

        self.main_page.click_subpanel_item("test-zone")

        nav_panel_locator = NavigationPanelLocators.TREEVIEW
        element = browser.locator(nav_panel_locator).get_by_text(rack_name, exact=True).first

        if element.is_visible():
            logger.debug(f"Rack with name '{rack_name}' found")
            return True

        logger.debug(f"Rack with name '{rack_name}' not found")
        return False

    def _create_rack(self, browser: Page, rack_data: CreateRackData) -> None:
        """Создает стойку.

        Args:
            browser: Страница Playwright
            rack_data: Данные стойки для создания
        """

        logger.debug(f"Creating rack with name '{rack_data.name}'")

        # Нажимаем кнопку "Создать" на тулбаре
        self.location_page.click_create_button()

        # Нажимаем на плашку "Класс объекта учета"
        self.create_child_frame.open_object_class_combobox()

        # Из выпадающего меню выбираем пункт "Стойка"
        self.create_child_frame.select_object_class("Стойка")

        # Создаем форму создания стойки
        rack_form = CreateRackForm(browser)

        # Заполняем данные стойки
        fill_results = rack_form.fill_rack_data(rack_data)
        logger.debug(f"Fill results: {fill_results}")

        # Нажимаем кнопку создания
        self.create_child_frame.click_add_button()

        # Ждем появления alert с текстом
        expected_alert_text = f"Успешно создано"
        self.alert.check_alert_presence(expected_alert_text, timeout=7000)

        self.alert.check_alert_absence(expected_alert_text, timeout=7000)

        # Закрываем alert с текстом кнопкой 'Закрыть'
        try:
            self.alert.close_alert_by_text(expected_alert_text)
            logger.debug("Alert forcibly closed")
        except AssertionError:
            # Если уже закрылся - игнорируем
            logger.debug("Alert already closed by the time forcible close was attempted")

        logger.info(f"Rack '{rack_data.name}' created successfully")

    def _delete_rack(self, browser: Page, rack_name: str) -> None:
        """Удаляет стойку через контекстное меню.

        Args:
            browser: Страница Playwright
            rack_name: Имя стойки для удаления
        """

        # Находим элемент стойки в навигационной панели
        rack_element = browser.locator(
            NavigationPanelLocators.TREEVIEW
        ).get_by_text(rack_name, exact=True).first

        # Прокручиваем до элемента если нужно
        rack_element.scroll_into_view_if_needed()
        self.main_page.wait_for_timeout(500)

        # Проверяем и нажимаем кнопку "Изменить"
        rack_page = RackPage(browser)

        # Проверяем видимость и тултип кнопки
        rack_page.should_be_toolbar_buttons()

        # Кликаем на кнопку "Изменить"
        rack_page.click_edit_button()
        self.main_page.wait_for_timeout(1000)

        # Создаем экземпляр EditRackMaker
        rack_edit = EditRackMaker(browser, rack_name)

        # Используем метод для удаления
        rack_edit.click_remove_button()

        # Проверяем уведомление об успешном удалении
        expected_alert_text = "Успешно удалено"
        self.alert.check_alert_presence(expected_alert_text, timeout=7000)

        self.alert.check_alert_absence(expected_alert_text, timeout=7000)

        # Закрываем alert с текстом кнопкой 'Закрыть'
        try:
            self.alert.close_alert_by_text(expected_alert_text)
            logger.debug("Alert forcibly closed")
        except AssertionError:
            # Если уже закрылся - игнорируем
            logger.debug("Alert already closed by the time forcible close was attempted")

        logger.info(f"Rack '{rack_name}' deleted successfully")

    def test_rack_tab_content(self, browser: Page) -> None:
        """Тест содержимого вкладки 'Стойка'.

        Проверяет:
        1. Наличие и корректность заголовка панели с навигационной цепочкой
        2. Отображение и структуру обеих сторон стойки (лицевой и обратной)
        3. Наличие и функциональность кнопок панели инструментов
        4. Корректность отображения юнитов и устройств на стойке

        Args:
            browser: Экземпляр страницы Playwright для взаимодействия с UI
        """

        logger.debug(f"Starting test for rack tab content with rack: {self.RACK_NAME}")

        expected_toolbar_subtitles = [
            "test-zone",
            'chevron_right',
            self.RACK_NAME
        ]

        rack_page = RackPage(browser)
        rack_page.should_be_panel_header(expected_toolbar_subtitles)

        # Комплексная проверка отображения обеих сторон стойки с детальной информацией
        rack_page.should_be_rack_sides_displayed()

        # Проверка кнопки "Скрыть стойку"
        rack_page.should_have_hide_rack_button()

        # Проверка кнопки "Показать стойку"
        rack_page.should_have_show_rack_button()

        # Проверяем переключение между всеми вкладками стойки
        rack_page.check_tab_switching()

        # Проверям наличие кнопки редактирования
        rack_page.should_be_toolbar_buttons()
        rack_page.wait_for_timeout(1000)

        logger.debug("Test for rack tab content completed successfully")
