"""Тест создания дочернего элемента 'Стойка'."""

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 pages.location_page import LocationPage
from makers.edit_rack_maker import EditRackMaker
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("CREATE_RACK_TEST")
logger.setLevel("INFO")


class TestCreateRack:
    """Тест создания дочернего элемента типа 'Стойка'."""

    # Единое имя для тестовой стойки
    TEST_RACK_NAME = "Test-Rack-Create"

    # Для теста с дубликатом используем отдельное имя
    DUPLICATE_RACK_NAME = "Test-Rack-Duplicate"

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

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

        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(2000)
        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)

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

    @pytest.fixture
    def cleanup_racks(self, browser: Page):
        """Фикстура для очистки созданных стоек."""

        created_racks = []
        yield created_racks

        # После завершения теста удаляем созданные стойки
        if created_racks:
            logger.debug(f"Cleaning up racks: {created_racks}")

            self.main_page.wait_for_timeout(500)
            self.main_page.click_subpanel_item("test-zone")
            self.main_page.wait_for_timeout(1000)

            for rack_name in created_racks:
                if self._check_rack_existance(browser, rack_name):
                    logger.debug(f"Deleting rack '{rack_name}'...")
                    self.main_page.click_subpanel_item(rack_name, parent="test-zone")
                    self.main_page.wait_for_timeout(1000)
                    self._delete_rack(browser, rack_name)
                    self.main_page.click_subpanel_item("test-zone")
                    self.main_page.wait_for_timeout(500)

    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 _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 test_create_rack_content(self, browser: Page) -> None:
        """Тест проверки содержимого формы создания стойки."""

        self.main_page.wait_for_timeout(7000)

        # Проверяем что кнопка "Создать" доступна
        self.location_page.should_be_toolbar_buttons()

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

        # Проверяем заголовок формы создания
        self.create_child_frame.check_toolbar_title('Создать дочерний элемент в')

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

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

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

        # Проверяем, что основные поля присутствуют
        assert rack_form.get_content_item("name_input") is not None, "Name field not initialized"
        assert rack_form.get_content_item("usize_input") is not None, "Height field not initialized"
        assert rack_form.get_content_item("depth_input") is not None, "Depth field not initialized"

        logger.debug("Rack-specific fields are displayed correctly")
        self.create_child_frame.should_be_toolbar_buttons()

    def test_create_rack(self, browser: Page, cleanup_racks) -> None:
        """Тест создания дочернего элемента типа 'Стойка'."""

        logger.debug(f"Starting test with rack name: {self.TEST_RACK_NAME}")

        # Создаем данные стойки с расширенным набором полей
        rack_data = CreateRackData(
            name=self.TEST_RACK_NAME,
            usize="42",
            depth="1000",
            serial="TEST123456",
            inventory="INV-001",
            comment="Тестовая стойка для автоматизации",
            cable_entry="сверху",
            state="Введен в эксплуатацию",
            # owner="Владелец",
            # service_org="Обслуживающая организация",
            # project="Проект/Титул"
        )

        # Сохраняем имя стойки для очистки
        cleanup_racks.append(rack_data.name)

        # Проверяем, существует ли уже стойка с таким именем
        if self._check_rack_existance(browser, rack_data.name):
            logger.warning(f"Rack '{rack_data.name}' already exists. Deleting it before creating new one...")

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

            # Удаляем существующую стойку
            self._delete_rack(browser, rack_data.name)
            logger.debug(f"Existing rack '{rack_data.name}' deleted successfully")

        # Создаем новую стойку
        self._create_rack(browser, rack_data)

        # Проверяем, что стойка создана и отображается
        logger.debug(f"Verifying that rack '{rack_data.name}' was created...")
        self.main_page.click_main_navigation_panel_item("test-zone")

        rack_exists = self._check_rack_existance(browser, rack_data.name)
        assert rack_exists, f"Rack '{rack_data.name}' should be visible in navigation panel after creation"

        logger.debug(f"Rack '{rack_data.name}' is visible in navigation panel")
        logger.debug("Test for creating 'Rack' child element completed successfully")

    def test_create_rack_with_duplicate_name(self, browser: Page, cleanup_racks) -> None:
        """Тест создания стойки с уже существующим именем."""

        logger.debug(f"Starting test for creating rack with duplicate name: {self.DUPLICATE_RACK_NAME}")

        rack_name = self.DUPLICATE_RACK_NAME

        # Создаем первую стойку если её нет
        if not self._check_rack_existance(browser, rack_name):
            logger.debug(f"Creating first rack with name '{rack_name}'")

            first_rack_data = CreateRackData(
                name=rack_name,
                usize="42",
                depth="1000"
            )
            self._create_rack(browser, first_rack_data)
            cleanup_racks.append(rack_name)

        # Пытаемся создать вторую стойку с тем же именем
        logger.debug(f"Attempting to create second rack with name '{rack_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)

        duplicate_rack_data = CreateRackData(
            name=rack_name,
            usize="42",
            depth="450"
        )

        self.create_child_frame.check_toolbar_title('Создать дочерний элемент в')

        rack_form.fill_rack_data(duplicate_rack_data)
        self.create_child_frame.click_add_button()

        expected_alert_text = f"Имя {rack_name} уже используется"
        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.debug("System prevented creating rack with duplicate name")

    @pytest.mark.develop
    def test_required_fields_validation(self, browser: Page, cleanup_racks) -> None:
        """Тест проверки обязательных полей при создании стойки."""
        logger.debug("Starting required fields validation test")

        expected_alert_text_height = "поле Высота в юнитах должно быть заполнено"
        expected_alert_text_depth = "поле Глубина (мм) должно быть заполнено"
        expected_alert_text_name = "Поле Имя должно быть заполнено"

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

        # Открываем форму создания
        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)

        # ========== Тест 1: Обязательные поля имя, высота и глубина пустые ==========
        logger.debug("Test 1: Both required fields (height, depth) are empty")

        # Очищаем поля имя, высоты и глубины перед заполнением
        rack_form.clear_field("Имя")
        rack_form.clear_field("Высота в юнитах")
        rack_form.clear_field("Глубина (мм)")

        test_data_1 = CreateRackData(
            name="",
            usize="",
            depth=""
        )

        rack_form.fill_rack_data(test_data_1)
        self.create_child_frame.click_add_button()

        # Проверяем alert для имени, высоты, глубины
        self.alert.check_alert_presence(expected_alert_text_name, timeout=7000)
        self.alert.check_alert_presence(expected_alert_text_height, timeout=7000)
        self.alert.check_alert_presence(expected_alert_text_depth, timeout=7000)

        # Проверяем, закрылся ли автоматически alert для имени, высоты, глубины
        self.alert.check_alert_absence(expected_alert_text_name, timeout=7000)
        self.alert.check_alert_absence(expected_alert_text_height, timeout=500)
        self.alert.check_alert_absence(expected_alert_text_depth, timeout=500)

        # Проверяем подсветку полей
        field_status = rack_form.verify_required_fields_highlighted(["Высота в юнитах", "Глубина (мм)"])
        logger.debug(f"Field status after test 1: {field_status}")
        assert field_status.get("Высота в юнитах"), f"Height field should be highlighted, got: {field_status}"
        assert field_status.get("Глубина (мм)"), f"Depth field should be highlighted, got: {field_status}"

        # ========== Тест 2: Только высота заполнена ==========
        logger.debug("Test 2: Only height field is filled")

        # Очищаем поле глубины перед новым заполнением
        rack_form.clear_field("Глубина (мм)")

        test_data_2 = CreateRackData(
            name=self.TEST_RACK_NAME,
            usize="42",
            depth=""
        )

        rack_form.fill_rack_data(test_data_2)
        self.create_child_frame.click_add_button()

        # Проверяем alert для глубины
        self.alert.check_alert_presence(expected_alert_text_depth, timeout=7000)

        # Проверяем, закрылся ли автоматически alert для глубины
        self.alert.check_alert_absence(expected_alert_text_depth, timeout=7000)

        # Проверяем подсветку полей
        field_status = rack_form.verify_required_fields_highlighted(["Глубина (мм)"])
        logger.debug(f"Field status after test 2: {field_status}")
        assert field_status.get("Глубина (мм)"), f"Depth field should be highlighted, got: {field_status}"

        # ========== Тест 3: Только глубина заполнена ==========
        logger.debug("Test 3: Only depth field is filled")

        # Очищаем поле высоты перед новым заполнением
        rack_form.clear_field("Высота в юнитах")

        test_data_3 = CreateRackData(
            name=self.TEST_RACK_NAME,
            usize="",
            depth="1000"
        )

        rack_form.fill_rack_data(test_data_3)
        self.create_child_frame.click_add_button()

        # Проверяем alert для высоты
        self.alert.check_alert_presence(expected_alert_text_height, timeout=7000)

        # Проверяем, закрылся ли автоматически alert для высоты
        self.alert.check_alert_absence(expected_alert_text_height, timeout=7000)

        # Проверяем подсветку полей
        field_status = rack_form.verify_required_fields_highlighted(["Высота в юнитах"])
        logger.debug(f"Field status after test 3: {field_status}")
        assert field_status.get("Высота в юнитах"), f"Height field should be highlighted, got: {field_status}"

        # ========== Тест 4: Поле "Имя" не заполнено ==========
        logger.debug("Test 4: Name field is empty")

        # Очищаем поле имени
        rack_form.clear_field("Имя")

        test_data_4 = CreateRackData(
            name="",
            usize="42",
            depth="1000"
        )

        rack_form.fill_rack_data(test_data_4)
        self.create_child_frame.click_add_button()

        # Проверяем alert для имени
        self.alert.check_alert_presence(expected_alert_text_name, timeout=7000)

        # Проверяем, закрылся ли автоматически alert для высоты
        self.alert.check_alert_absence(expected_alert_text_name, timeout=7000)

        logger.debug("Test 4 completed: System correctly validates empty name field")

        # ========== Тест 5: Поле "Имя" не более 35 знаков ==========
        # разработчик должен ограничить длину имени - не более 35 знаков