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

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

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

logger = get_logger("RACK_TAB")

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


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

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

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

        locator_button = self.page.locator(PANEL_HEADER).\
                         locator(EDIT_BUTTON_ANCESTOR_DIV3).nth(0)
        self.edit_button = TooltipButton(page, locator_button, "edit")

        self.toolbar = ToolbarComponent(page, "")
        self.toolbar.add_tooltip_button(locator_button, "edit")

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

        Args:
            timeout: Время ожидания в миллисекундах (по умолчанию 15000)

        Raises:
            TimeoutError: Если загрузка не завершилась в указанное время
        """
        logger.info("Ожидание загрузки интерфейса стойки...")

        # Ждем появления основного контейнера
        main_container = self.page.locator(RackLocators.MAIN_CONTAINER)
        expect(main_container).to_be_visible(timeout=timeout)

        # Ждем появления юнитов
        units = self.page.locator(RackLocators.ALL_UNITS)
        expect(units).to_have_count(20, timeout=timeout)

        logger.info("Интерфейс стойки загружен")

    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_tab(self, tab_name: str) -> None:
        """
        Переключается на указанную вкладку.

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

        Raises:
            AssertionError: Если вкладка не найдена или недоступна
        """
        logger.info(f"Переключение на вкладку '{tab_name}'...")

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

        if tab.count() == 0:
            raise AssertionError(f"Вкладка '{tab_name}' не найдена")

        # Проверяем активность ДО клика
        if self.is_tab_active(tab_name):
            logger.info(f"Вкладка '{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

        if not target_tab:
            raise AssertionError(f"Не найдена видимая/доступная вкладка '{tab_name}'")

        # Кликаем на вкладку
        logger.info(f"Клик на вкладку '{tab_name}'...")
        target_tab.click()

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

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

    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_events_tab(self) -> None:
        """Переключается на вкладку 'События'."""
        self.switch_to_tab("События")

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

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

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

        Returns:
            bool: True если вкладка активна, False в противном случае
        """
        # Метод 1: Проверяем по активному классу и тексту, метод быстый, если надо универсальный оставояем метод 2 - медленный
        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.info(f"Вкладка '{tab_name}' активна (через класс активной вкладки)")
                return True

        # Метод 2: Проверяем по классам у конкретной вкладки
        tab = self.page.locator(RackLocators.TAB_BY_NAME.format(tab_name))

        if tab.count() > 0:
            for i in range(tab.count()):
                element = tab.nth(i)
                if element.is_visible() and element.is_enabled():
                    element_class = element.get_attribute("class") or ""
                    is_active = any(
                        active_class in element_class
                        for active_class in RackLocators.ACTIVE_TAB_CLASSES
                    )

                    if is_active:
                        logger.info(f"Вкладка '{tab_name}' активна (классы: {element_class})")
                        return True

        logger.info(f"Вкладка '{tab_name}' не активна")
        return False

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

        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.info(f"Всего найдено элементов верхних вкладок: {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.info(f"Найдена верхняя вкладка: '{tab_text}'")

        logger.info(f"Найдены доступные верхние вкладки: {tabs}")
        return tabs

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

        Args:
            tab_name: Название вкладки для ожидания
            timeout: Время ожидания в миллисекундах

        Raises:
            AssertionError: Если вкладка не активирована в течение таймаута
        """
        logger.info(f"Ожидание активации вкладки '{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.info(f"Вкладка '{tab_name}' успешно активирована")
                return
            self.page.wait_for_timeout(100)

        raise AssertionError(f"Вкладка '{tab_name}' не активирована в течение {timeout}мс")

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

        Raises:
            AssertionError: Если кнопки недоступны или подсказки неверны.
        """
        logger.info("Проверка кнопок панели инструментов...")

        self.toolbar.check_button_visibility("edit")
        self.toolbar.check_button_tooltip("edit", "Изменить")
        self.toolbar.get_button_by_name("edit").click()

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

        Raises:
            AssertionError: Если стороны стойки не отображаются корректно
        """
        logger.info("Проверка отображения и структуры сторон стойки...")

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

        # БАЗОВАЯ ПРОВЕРКА: обе стороны отображаются
        logger.info("--- Базовая проверка отображения сторон ---")

        front_side_section = self.page.locator(RackLocators.FRONT_SIDE_SECTION).first
        expect(front_side_section).to_be_visible(timeout=10000)
        logger.info("Секция лицевой стороны найдена")

        back_side_section = self.page.locator(RackLocators.BACK_SIDE_SECTION).first
        expect(back_side_section).to_be_visible(timeout=10000)
        logger.info("Секция обратной стороны найдена")

        # Проверяем заголовки
        front_side_title = front_side_section.locator(RackLocators.FRONT_SIDE_TITLE)
        expect(front_side_title).to_be_visible(timeout=5000), "Заголовок 'Лицевая сторона' не отображается"
        logger.info("Заголовок 'Лицевая сторона' отображается")

        back_side_title = back_side_section.locator(RackLocators.BACK_SIDE_TITLE)
        expect(back_side_title).to_be_visible(timeout=5000), "Заголовок 'Обратная сторона' не отображается"
        logger.info("Заголовок 'Обратная сторона' отображается")

        # Проверяем позиции юнитов
        unit_positions = self.page.locator(RackLocators.UNIT_POSITIONS)
        total_positions = unit_positions.count()
        logger.info(f"Всего позиций юнитов: {total_positions}")
        assert total_positions > 0, "Не найдено позиций юнитов"

        # Детальная проверка лицевой стороны
        logger.info("--- Детальная проверка лицевой стороны ---")
        self._check_front_side_details(front_side_section)

        # Детальная проверка обратной стороны
        logger.info("--- Детальная проверка обратной стороны ---")
        self._check_back_side_details(back_side_section)

        logger.info("Все проверки сторон стойки пройдены успешно")

    def _check_front_side_details(self, front_side_section) -> None:
        """
        Проверка структуры лицевой стороны стойки.

        Args:
            front_side_section: Локатор секции лицевой стороны

        Raises:
            AssertionError: Если структура лицевой стороны некорректна
        """
        # Проверяем юниты в секции лицевой стороны
        front_side_units = front_side_section.locator(RackLocators.FRONT_SIDE_UNITS)
        unit_count = front_side_units.count()
        logger.info(f"Найдено юнитов на лицевой стороне: {unit_count}")
        assert unit_count >= 1, f"Не найдено юнитов на лицевой стороне. Ожидалось минимум 1, найдено {unit_count}"

        # Проверяем наличие устройств на лицевой стороне
        front_side_devices = front_side_section.locator(RackLocators.FRONT_SIDE_DEVICES)
        device_count = front_side_devices.count()
        logger.info(f"Найдено физических устройств на лицевой стороне: {device_count}")

        if device_count > 0:
            for i in range(device_count):
                device = front_side_devices.nth(i)
                device_title = device.get_attribute("title")
                device_classes = device.get_attribute("class") or ""
                logger.info(f"  Устройство {i}: title='{device_title}', classes='{device_classes}'")

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

        Args:
            back_side_section: Локатор секции обратной стороны

        Raises:
            AssertionError: Если структура обратной стороны некорректна
        """
        # Проверяем юниты в секции обратной стороны
        back_side_units = back_side_section.locator(RackLocators.BACK_SIDE_UNITS)
        unit_count = back_side_units.count()
        logger.info(f"Найдено юнитов на обратной стороне: {unit_count}")
        assert unit_count >= 1, f"Не найдено юнитов на обратной стороне. Ожидалось минимум 1, найдено {unit_count}"

        # Проверяем наличие устройств на обратной стороне
        back_side_devices = back_side_section.locator(RackLocators.BACK_SIDE_DEVICES)
        device_count = back_side_devices.count()
        logger.info(f"Найдено физических устройств на обратной стороне: {device_count}")

        if device_count > 0:
            for i in range(device_count):
                device = back_side_devices.nth(i)
                device_title = device.get_attribute("title")
                device_classes = device.get_attribute("class") or ""
                logger.info(f"  Устройство {i}: title='{device_title}', classes='{device_classes}'")

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

        Args:
            expected_toolbar_title_items: Ожидаемые элементы заголовка

        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} and expected {expected_toolbar_title_items}")

        self.toolbar.check_button_visibility("edit")


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

        Raises:
            AssertionError: Если переключение на одну или более вкладок не удалось
        """
        logger.info("Тестирование функциональности переключения вкладок стойки...")

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

        logger.info(f"Тестируемые определенные вкладки: {defined_tabs}")

        successful_switches = 0
        failed_switches = []

        # Тестируем переключение на каждую определенную вкладку
        for tab_name in defined_tabs:
            logger.info(f"Тестирование переключения на вкладку '{tab_name}'...")

            # Проверяем существование локатора для этой вкладки
            tab_locator = RackLocators.TAB_BY_NAME.format(tab_name)
            tab_elements = self.page.locator(tab_locator)

            # Проверяем наличие элементов через count()
            if tab_elements.count() == 0:
                logger.warning(f"Вкладка '{tab_name}' не найдена на странице")
                failed_switches.append(f"Вкладка '{tab_name}' не найдена")
                continue

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

            if not target_tab:
                logger.warning(f"Не найдена видимая/доступная вкладка '{tab_name}'")
                failed_switches.append(f"Вкладка '{tab_name}' не видима/не доступна")
                continue

            # Переключаемся на вкладку
            logger.info(f"Переключение на вкладку '{tab_name}'...")

            # Проверяем активность ДО клика
            if self.is_tab_active(tab_name):
                logger.info(f"Вкладка '{tab_name}' уже активна")
                successful_switches += 1
                continue

            # Кликаем на вкладку с таймаутом
            target_tab.click(timeout=5000)

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

            # Проверяем, что вкладка активна
            if not self.is_tab_active(tab_name):
                logger.warning(f"Вкладка '{tab_name}' не активна после переключения")
                failed_switches.append(f"Вкладка '{tab_name}' не активна после клика")
                continue

            logger.info(f"Успешно переключено на вкладку '{tab_name}'")
            successful_switches += 1

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

        # Формируем итоговый отчет
        logger.info("=== РЕЗУЛЬТАТЫ ПЕРЕКЛЮЧЕНИЯ ВКЛАДОК ===")
        logger.info(f"Успешных переключений: {successful_switches}/{len(defined_tabs)}")

        if failed_switches:
            logger.info("Неудачные переключения:")
            for failure in failed_switches:
                logger.info(f"  - {failure}")

        # Требуем успешного переключения на все определенные вкладки
        if successful_switches < len(defined_tabs):
            raise AssertionError(
                f"Тест переключения вкладок не пройден. "
                f"Только {successful_switches} из {len(defined_tabs)} определенных вкладок переключены успешно. "
                f"Ошибки: {', '.join(failed_switches)}"
            )

        logger.info(f"Все {successful_switches} определенных вкладок успешно переключены!")
