"""Модуль тестов вкладки 'Стойка'.

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

"""
from typing import Optional
from playwright.sync_api import Page, expect
from tools.logger import get_logger
from locators.rack_locators import RackLocators
from elements.tooltip_button_element import TooltipButton
from components.toolbar_component import ToolbarComponent
from pages.base_page import BasePage


logger = get_logger("RACK_PAGE")

logger.setLevel("INFO")

# Специфичные локаторы оставленые в основном коде
PANEL_HEADER = "//span[text()='Объекты']/following-sibling::i"
TOOLBAR_CONTENT = "//div[@class='v-toolbar__content']"
PANEL_HEADER_ANCESTOR_DIV2 = "xpath=/ancestor::div[2]"


class RackPage(BasePage):
    """Класс для работы с вкладкой стойки оборудования."""

    def __init__(self, page: Page) -> None:
        """
        Инициализирует объект вкладки стойки.

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

        super().__init__(page)

        # Кнопка "Изменить"
        locator_button = self.page.locator(RackLocators.EDIT_BUTTON)
        self.edit_button = TooltipButton(page, locator_button, "edit")

         # Кнопка "Скрыть стойку"
        hide_button_locator = self.page.locator(RackLocators.HIDE_RACK_BUTTON)
        self.hide_button = TooltipButton(page, hide_button_locator, "hide_rack")

        # Кнопка "Показать стойку"
        show_button_locator = self.page.locator(RackLocators.SHOW_RACK_BUTTON)
        self.show_button = TooltipButton(page, show_button_locator, "show_rack")

        self.toolbar = ToolbarComponent(page, "")
        self.toolbar.add_tooltip_button(locator_button, "edit")
        self.toolbar.add_tooltip_button(hide_button_locator, "hide_rack")
        self.toolbar.add_tooltip_button(show_button_locator, "show_rack")

    # Действия

    def click_edit_button(self) -> None:
        """ Кликает на кнопку 'Изменить'."""

        self.toolbar.get_button_by_name("edit").click()
        self.wait_for_timeout(1000)

    def get_available_tabs(self) -> list[str]:
        """
        Возвращает список доступных вкладок.

        Returns:
            list[str]: Список названий доступных вкладок
        """

        tabs = []

        # Используем локатор для верхних вкладок
        tab_elements = self.page.locator(RackLocators.ALL_TABS)

        # Ждем появления элементов
        tab_elements.first.wait_for(state="visible", timeout=5000)

        total_count = tab_elements.count()
        logger.debug("Total top tab elements found: %d", total_count)

        for i in range(total_count):
            element = tab_elements.nth(i)

            # Проверяем видимость и доступность элемента
            if element.is_visible() and element.is_enabled():
                tab_text = element.text_content()
                if tab_text:
                    tab_text = tab_text.strip()
                    if tab_text and tab_text not in tabs:
                        tabs.append(tab_text)
                        logger.debug("Top tab found: '%s'", tab_text)

        logger.debug("Available top tabs found: %s", tabs)
        return tabs

    def get_current_active_side(self) -> Optional[str]:
        """
        Возвращает текущую активную сторону стойки.

        Returns:
            Optional[str]: "Лицевая сторона", "Обратная сторона" или None если ни одна не активна
        """

        # Проверяем конкретно кнопку "Лицевая сторона"
        front_btn = self.page.locator(RackLocators.FRONT_SIDE_BUTTON)
        if front_btn.count() > 0:
            classes = front_btn.first.get_attribute("class") or ""
            if "primary--text" in classes.split():
                return "Лицевая сторона"

        # Проверяем конкретно кнопку "Обратная сторона"
        back_btn = self.page.locator(RackLocators.BACK_SIDE_BUTTON)
        if back_btn.count() > 0:
            classes = back_btn.first.get_attribute("class") or ""
            if "primary--text" in classes.split():
                return "Обратная сторона"

        return None

    def get_toolbar_title(self) -> list[str]:
        """
        Получает заголовок панели инструментов.

        Returns:
            list[str]: Список элементов заголовка панели инструментов
        """

        toolbar_title_locator = self.page.locator(PANEL_HEADER).\
                         locator(PANEL_HEADER_ANCESTOR_DIV2).\
                         get_by_role("navigation").\
                         locator(TOOLBAR_CONTENT)

        return self.toolbar.get_toolbar_composite_title_text(toolbar_title_locator)

    def switch_to_composition_tab(self) -> None:
        """Переключается на вкладку 'Состав'."""

        self.switch_to_tab("Состав")

    def switch_to_events_tab(self) -> None:
        """Переключается на вкладку 'События'."""

        self.switch_to_tab("События")

    def switch_to_general_info_tab(self) -> None:
        """Переключается на вкладку 'Общая информация'."""

        self.switch_to_tab("Общая информация")

    def switch_to_maintenance_tab(self) -> None:
        """Переключается на вкладку 'Обслуживание'."""

        self.switch_to_tab("Обслуживание")

    def switch_to_services_tab(self) -> None:
        """Переключается на вкладку 'Сервисы'."""

        self.switch_to_tab("Сервисы")

    def switch_to_tab(self, tab_name: str) -> None:
        """
        Переключается на указанную вкладку.

        Args:
            tab_name (str): Название вкладки для переключения

        Raises:
            AssertionError: Если вкладка не найдена или недоступна
        """

        logger.debug("Switching to tab '%s'...", tab_name)

        tab = self.page.locator(RackLocators.TAB_BY_NAME.format(tab_name))

        assert tab.count() > 0, f"Tab '{tab_name}' not found"

        # Проверяем активность ДО клика
        if self.is_tab_active(tab_name):
            logger.debug("Tab '%s' is already active", tab_name)
            return

        # Находим первую видимую вкладку с нужным именем
        target_tab = None
        for i in range(tab.count()):
            element = tab.nth(i)
            if element.is_visible() and element.is_enabled():
                target_tab = element
                break

        assert target_tab is not None, f"No visible/available tab '{tab_name}' found"

        # Кликаем на вкладку
        logger.debug("Clicking on tab '%s'...", tab_name)
        target_tab.click()

        # Ждем изменения активной вкладки
        self._wait_for_tab_activation(tab_name)

        # Ждем загрузки контента
        self.wait_for_timeout(500)

    def wait_for_rack_loading(self) -> None:
        """Ожидает загрузки интерфейса стойки."""

        logger.debug("Waiting for rack interface to load...")

        # Проверяем наличие кнопок переключения сторон
        front_button = self.page.locator(RackLocators.FRONT_SIDE_BUTTON)
        back_button = self.page.locator(RackLocators.BACK_SIDE_BUTTON)

        expect(front_button).to_be_visible(timeout=5000)
        expect(back_button).to_be_visible(timeout=5000)
        logger.debug("Side toggle buttons loaded")

        # Проверяем, что есть активная кнопка
        active_button = self.page.locator(RackLocators.ACTIVE_SIDE_BUTTON)
        if active_button.count() > 0:
            logger.debug("Active side button found")
        else:
            logger.warning("No active side button found")

        # Проверяем наличие основного контейнера
        main_container = self.page.locator(RackLocators.MAIN_CONTAINER)
        if main_container.count() == 0:
            logger.warning("Main rack container not found")
        else:
            logger.debug("Main rack container found (count: %d)", main_container.count())
            expect(main_container.first).to_be_attached()

        # Проверяем наличие позиций юнитов
        unit_positions = self.page.locator(RackLocators.UNIT_POSITIONS)
        if unit_positions.count() > 0:
            logger.debug("Unit positions found: %d", unit_positions.count())
            if unit_positions.first.text_content():
                content = unit_positions.first.text_content().strip()
                logger.debug("First position: %s", content)

        # Проверяем наличие кнопок добавления
        open_buttons = self.page.locator(RackLocators.ADD_CIRCLE_BUTTON)
        if open_buttons.count() > 0:
            logger.debug("'add_circle' buttons found: %d", open_buttons.count())

        logger.debug("Rack interface loaded")

    # Проверки

    def check_physical_devices_presence(self) -> None:
        """Проверяет наличие физических устройств на стойке."""

        # Поиск устройств по классу parent-class
        devices = self.page.locator(RackLocators.DEVICE_ELEMENTS)
        device_count = devices.count()

        if device_count > 0:
            # Выводим информацию только о первом устройстве
            first_device = devices.first
            device_id = first_device.get_attribute("id") or "No id"
            device_title = first_device.get_attribute("title") or "No title"

            logger.debug(
                "Devices found: %d (first: ID=%s, Title=%s)",
                device_count, device_id, device_title
            )
        else:
            logger.debug("No devices detected")

    def check_tab_switching(self) -> None:
        """
        Проверяет переключение между вкладками стойки.

        Raises:
            AssertionError: Если не удалось переключиться на все вкладки
        """

        logger.debug("Testing rack tab switching functionality...")

        # Вкладки в правильном порядке
        defined_tabs = [
            "Состав",
            "Общая информация",
            "Обслуживание",
            "События",
            "Сервисы"
        ]

        logger.debug("Defined tabs to test: %s", defined_tabs)

        successful_switches = 0
        failed_switches = []

        # Тестируем переключение на каждую определенную вкладку
        for tab_name in defined_tabs:
            logger.debug("Testing switch to tab '%s'...", tab_name)

            try:
                # Переключаемся на вкладку
                self.switch_to_tab(tab_name)

                # Проверяем, что вкладка активна
                if self.is_tab_active(tab_name):
                    logger.debug("Successfully switched to tab '%s'", tab_name)
                    successful_switches += 1
                else:
                    logger.warning("Tab '%s' not active after switching", tab_name)
                    failed_switches.append(f"Tab '{tab_name}' is not active after click")

            except (AssertionError, TimeoutError) as e:
                # Ловим только конкретные исключения, которые могут возникнуть при переключении вкладок
                logger.error("Error switching to tab '%s': %s", tab_name, e)
                failed_switches.append(f"Tab '{tab_name}' error: {str(e)}")

            # Небольшая пауза между переключениями
            self.wait_for_timeout(1000)

        # Формируем итоговый отчет
        logger.debug("=== TAB SWITCHING RESULTS ===")
        logger.debug("Successful switches: %d/%d", successful_switches, len(defined_tabs))

        if failed_switches:
            logger.debug("Failed switches:")
            for failure in failed_switches:
                logger.debug("  - %s", failure)

        # Требуем успешного переключения на все определенные вкладки
        assert successful_switches == len(defined_tabs), (
            f"Tab switching test failed. "
            f"Only {successful_switches} out of {len(defined_tabs)} defined tabs "
            f"were successfully switched. "
            f"Errors: {', '.join(failed_switches)}"
        )

        logger.debug("All %d defined tabs successfully switched!", successful_switches)

    def is_tab_active(self, tab_name: str) -> bool:
        """
        Проверяет, активна ли указанная вкладка.

        Args:
            tab_name (str): Название вкладки для проверки

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

        # Проверяем по активному классу и тексту
        active_tab = self.page.locator(RackLocators.ACTIVE_TAB)

        if active_tab.count() > 0 and active_tab.first.is_visible():
            active_text = active_tab.first.text_content()
            if active_text and active_text.strip() == tab_name:
                logger.debug("Tab '%s' is active (via active tab class)", tab_name)
                return True

        logger.debug("Tab '%s' is not active", tab_name)
        return False

    def should_be_panel_header(self, expected_toolbar_title_items: list[str]) -> None:
        """
        Проверяет наличие и корректность заголовка панели.

        Args:
            expected_toolbar_title_items (list[str]): Ожидаемые элементы заголовка

        Raises:
            AssertionError: Если заголовок панели не соответствует ожиданиям
        """

        panel_header_locator = self.page.locator(PANEL_HEADER)
        expect(panel_header_locator).to_be_visible(), "Panel header 'Объекты'"

        if panel_header_locator.inner_text() != 'chevron_right':
            assert False, "No separator 'chevron_right' after header 'Объекты'"

        actual_toolbar_title_items = self.get_toolbar_title()

        self.check_lists_equals(
            actual_toolbar_title_items,
            expected_toolbar_title_items,
            f"Miscomparison actual {actual_toolbar_title_items} "
            f"and expected {expected_toolbar_title_items}"
        )

    def should_be_rack_sides_displayed(self) -> None:
        """
        Проверка отображения и структуры сторон стойки.

        Raises:
            AssertionError: Если стороны стойки не отображаются корректно
        """

        logger.debug("Checking rack sides display and structure...")

        # Ожидаем загрузки
        self.wait_for_rack_loading()

        # БАЗОВАЯ ПРОВЕРКА: наличие кнопок переключения сторон

        front_side_button = self.page.locator(RackLocators.FRONT_SIDE_BUTTON)
        back_side_button = self.page.locator(RackLocators.BACK_SIDE_BUTTON)

        # Проверяем наличие кнопок
        expect(front_side_button).to_be_visible(timeout=5000), \
            "Front side button not found"
        expect(back_side_button).to_be_visible(timeout=5000), \
            "Back side button not found"

        logger.debug("Side toggle buttons found")

        # Проверяем, какая сторона активна по умолчанию
        current_active = self.get_current_active_side()
        logger.debug("Current active side: %s", current_active)

        # Дополнительная проверка устройств
        self.check_physical_devices_presence()

        # ПРОВЕРКА ЛИЦЕВОЙ СТОРОНЫ
        self._check_side_details("Лицевая сторона", front_side_button)

        # ПРОВЕРКА ОБРАТНОЙ СТОРОНЫ
        self._check_side_details("Обратная сторона", back_side_button)

        # Возвращаемся на исходную активную сторону
        if current_active:
            logger.debug("Returning to original active side: %s", current_active)
            if current_active == "Лицевая сторона":
                front_side_button.click()
            else:
                back_side_button.click()
            self.wait_for_timeout(1000)

            final_active = self.get_current_active_side()
            logger.debug("Final active side: %s", final_active)

        logger.debug("All rack sides checks passed successfully")

    def should_be_toolbar_buttons(self) -> None:
        """
        Проверяет наличие и функциональность кнопок тулбара.

        Raises:
            AssertionError: Если кнопки недоступны или подсказки неверны
        """

        logger.debug("Checking toolbar buttons...")

        # Проверяем основные кнопки
        self.toolbar.check_button_visibility("edit")
        self.toolbar.check_button_tooltip("edit", "Изменить")

        # Кликаем на кнопку "Изменить" для проверки функциональности
        #self.toolbar.get_button_by_name("edit").click()


    def should_have_hide_rack_button(self) -> None:
        """
        Проверка кнопки "Скрыть стойку".

        Raises:
            AssertionError: Если кнопка не отображается или не работает
        """
        logger.debug("Checking 'Hide rack' button...")

        # Проверяем видимость кнопки
        self.toolbar.check_button_visibility("hide_rack")
        self.toolbar.check_button_tooltip("hide_rack", "Скрыть стойку")

        # Получаем общий контейнер стойки до клика
        rack_container = self.page.locator(RackLocators.RACK_CONTAINER)

        # Проверяем, что контейнер существует
        expect(rack_container).to_be_visible(timeout=5000)

        # Кликаем на кнопку "Скрыть стойку"
        self.toolbar.get_button_by_name("hide_rack").click()
        self.wait_for_timeout(2000)

        # Проверяем, что общий контейнер стойки теперь скрыт (имеет display: none)
        expect(rack_container).to_have_css("display", "none", timeout=5000)
        logger.debug("Rack container successfully hidden (display: none)")

        logger.debug("'Hide rack' button test completed successfully")

    def should_have_show_rack_button(self) -> None:
        """
        Проверка кнопки "Показать стойку".

        Raises:
            AssertionError: Если кнопка не отображается или не работает
        """
        logger.debug("Checking 'Show rack' button...")

        # Проверяем видимость кнопки
        self.toolbar.check_button_visibility("show_rack")
        self.toolbar.check_button_tooltip("show_rack", "Показать стойку")

        # Получаем общий контейнер стойки
        rack_container = self.page.locator(RackLocators.RACK_CONTAINER)

        # Проверяем, что контейнер существует
        expect(rack_container).to_be_attached(timeout=5000)

        # Кликаем на кнопку "Показать стойку"
        self.toolbar.get_button_by_name("show_rack").click()
        self.wait_for_timeout(2000)  # Даем время для применения стилей

        # Проверяем, что общий контейнер стойки теперь видим (display не равен "none")
        expect(rack_container).not_to_have_css("display", "none", timeout=5000)
        logger.debug("Rack container successfully shown (display is not 'none')")

        logger.debug("'Show rack' button test completed successfully")

    # Вспомогательные методы

    def _check_side_details(self, side_name: str, side_button) -> None:
        """
        Проверка структуры конкретной стороны стойки.

        Args:
            side_name (str): Название стороны для логов
            side_button: Локатор кнопки стороны

        Raises:
            AssertionError: Если структура стороны некорректна
        """

        logger.debug("Checking %s...", side_name)

        # Логируем текущее состояние кнопки перед кликом
        button_classes = side_button.get_attribute("class") or ""
        logger.debug("Button classes before click: %s", button_classes)

        # Проверяем, активна ли уже эта сторона
        current_active = self.get_current_active_side()
        logger.debug("Current active side (before click): '%s'", current_active)

        if current_active == side_name:
            logger.debug("%s is already active", side_name)
        else:
            # Если не активна, кликаем для переключения
            logger.debug("Switching to %s...", side_name)
            side_button.click()
            # Даем время на перерисовку классов (увеличиваем время)
            self.wait_for_timeout(2500)

            # Проверяем классы после клика
            button_classes_after = side_button.get_attribute("class") or ""
            logger.debug("Button classes after click: %s", button_classes_after)

        # Проверяем, что нужная сторона стала активной
        active_side = self.get_current_active_side()
        logger.debug("Active side after switching: '%s'", active_side)

        assert active_side == side_name, \
            f"Wrong side is active: '{active_side}', expected: '{side_name}'"

        logger.debug("%s successfully activated", side_name)

        # Проверяем позиции юнитов
        unit_positions = self.page.locator(RackLocators.UNIT_POSITIONS)
        total_positions = unit_positions.count()
        logger.debug("Total unit positions: %d", total_positions)
        assert total_positions > 0, f"No unit positions found on {side_name}"

        # Проверяем юниты
        all_units = self.page.locator(RackLocators.ALL_UNITS)
        all_units_count = all_units.count()
        units_per_side = all_units_count // 2
        logger.debug("Units on %s: %d", side_name, units_per_side)

        # Проверяем устройства
        devices = self.page.locator(RackLocators.DEVICE_ELEMENTS)
        device_count = devices.count()

        if device_count > 0:
            # Выводим информацию только о первом устройстве
            first_device = devices.first
            device_id = first_device.get_attribute("id") or "No id"
            device_title = first_device.get_attribute("title") or "No title"
            device_classes = first_device.get_attribute("class") or "No classes"

            # Ищем слоты внутри устройства
            slots = first_device.locator(RackLocators.DEVICE_SLOTS)
            slot_count = slots.count()

            logger.debug("Devices found: %d (showing first)", device_count)
            logger.debug("  Device: ID=%s", device_id)
            logger.debug("          Title: %s", device_title)
            logger.debug("          Classes: %s", device_classes)
            logger.debug("          Slots: %d", slot_count)
        else:
            logger.debug("No devices detected")

        logger.debug("%s check completed successfully", side_name)

    def _wait_for_tab_activation(self, tab_name: str, timeout: int = 5000) -> None:
        """
        Ожидает активации вкладки.

        Args:
            tab_name (str): Название вкладки для ожидания
            timeout (int, optional): Время ожидания в миллисекундах, по умолчанию 5000

        Raises:
            AssertionError: Если вкладка не активирована в течение таймаута
        """

        logger.debug("Waiting for tab '%s' activation...", tab_name)

        start_time = self.page.evaluate("Date.now()")
        while self.page.evaluate("Date.now()") - start_time < timeout:
            if self.is_tab_active(tab_name):
                logger.debug("Tab '%s' successfully activated", tab_name)
                return
            self.wait_for_timeout(100)

        assert False, f"Tab '{tab_name}' not activated within {timeout}ms"
