"""Модуль фрейма создания дочернего элемента."""

import re
from typing import Dict, Any, Optional
from playwright.sync_api import Page, Locator
from tools.logger import get_logger
from locators.rack_locators import RackLocators
from locators.selection_bar_locators import SelectionBarLocators
from components.alert_component import AlertComponent
from components.base_component import BaseComponent
from components.toolbar_component import ToolbarComponent
from components_derived.selection_bar_component import SelectionBarComponent
from forms.create_rack_form import CreateRackForm, CreateRackData


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


class CreateElementFrame(BaseComponent):
    """Фрейм создания дочернего элемента."""

    def __init__(self, page: Page) -> None:
        """
        Инициализирует фрейм создания дочернего элемента.

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

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

        # Инициализация компонентов
        self.toolbar = ToolbarComponent(page, "Создать дочерний элемент в")
        self.selection_bar = SelectionBarComponent(page, "Класс объекта учета")
        self.alert = AlertComponent(page)

        # Кнопка "Добавить" - первая кнопка в тулбаре фрейма создания
        add_button_locator = self.page.get_by_role("navigation").filter(
            has_text="Создать дочерний элемент в"
        ).get_by_role("button").nth(0)

        # Кнопка "Отменить" - используем рабочий локатор
        cancel_button_locator = self.page.get_by_role("navigation").filter(
            has_text=re.compile('Создать дочерний элемент в')
        ).get_by_role("button").nth(1)

        # Инициализация кнопок
        self.toolbar.add_tooltip_button(add_button_locator, "add")
        self.toolbar.add_tooltip_button(cancel_button_locator, "cancel")

    # Делегирование методов форме создания стойки

    def fill_rack_data(self, rack_data: CreateRackData) -> Dict[str, int]:
        """
        Заполняет поля формы создания стойки.

        Args:
            rack_data: Данные для заполнения

        Returns:
            Словарь с результатами заполнения
        """
        return self.rack_form.fill_rack_data(rack_data)

    def clear_field(self, field_name: str) -> None:
        """
        Очищает указанное поле формы.

        Args:
            field_name: Название поля для очистки
        """
        self.rack_form.clear_field(field_name)

    def get_field_value(self, field_name: str) -> Optional[str]:
        """
        Получает значение поля формы.

        Args:
            field_name: Название поля

        Returns:
            Значение поля или None если поле не найдено
        """
        return self.rack_form.get_field_value(field_name)

    def is_field_highlighted_as_error(self, field_name: str) -> bool:
        """
        Проверяет, подсвечено ли поле как ошибочное.

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

        Returns:
            bool: True если поле подсвечено ошибкой
        """
        return self.rack_form.is_field_highlighted_as_error(field_name)

    def wait_for_field_error(self, field_name: str, timeout: int = 5000) -> bool:
        """
        Ожидает появления подсветки ошибки на поле.

        Args:
            field_name: Название поля
            timeout: Таймаут в миллисекундах

        Returns:
            bool: True если ошибка появилась
        """
        return self.rack_form.wait_for_field_error(field_name, timeout)

    # Оригинальные методы фрейма

    def clear_combobox_field(self, field_name: str) -> None:
        """
        Очищает combobox поле по его названию.

        Args:
            field_name (str): Название поля для очистки
        """
        logger.debug(f"Clearing combobox field '{field_name}'...")

        # Получаем контейнер формы
        container_locator = self.page.locator(RackLocators.CREATE_RACK_FORM_CONTAINER).nth(1)
        fields_locators = self.get_input_fields_locators(container_locator)

        if field_name not in fields_locators:
            logger.warning(f"Field '{field_name}' not found in form")
            return

        field_container = fields_locators[field_name]
        field_container.scroll_into_view_if_needed()
        self.wait_for_timeout(300)

        if not field_container.is_visible():
            logger.debug(f"Field '{field_name}' is not visible after scrolling")
            return

        # Ищем кнопку закрытия (крестик) внутри контейнера поля
        close_button = field_container.locator("i.mdi-close").first

        if close_button.count() > 0:
            close_button.click(force=True)
            self.wait_for_timeout(300)
            logger.debug(f"Combobox field '{field_name}' cleared using close button")
        else:
            logger.debug(f"Close button (i.mdi-close) not found for field '{field_name}'")

    def click_add_button(self) -> None:
        """Кликает на кнопку 'Добавить'."""
        logger.debug("Clicking on 'Add' button...")
        self.toolbar.click_button("add")

    def click_cancel_button(self) -> None:
        """Кликает на кнопку 'Отменить'."""
        logger.debug("Clicking on 'Cancel' button...")
        self.toolbar.click_button("cancel")

    def get_selected_object_class(self) -> str:
        """
        Получает выбранный класс объекта учета.

        Returns:
            str: Выбранный класс объекта или пустая строка если ничего не выбрано
        """
        return self.selection_bar.get_selection_bar_title()

    def is_field_filled(self, field_name: str, container_locator: Locator = None) -> bool:
        """
        Проверяет, заполнено ли combobox или текстовое поле.

        Args:
            field_name (str): Название поля для проверки
            container_locator (Locator, optional): Локатор контейнера формы

        Returns:
            bool: True если поле заполнено, False в противном случае
        """
        logger.debug(f"Checking if field '{field_name}' is filled...")

        if container_locator is None:
            container_locator = self.page.locator(RackLocators.CREATE_RACK_FORM_CONTAINER).nth(1)

        fields_locators = self.get_input_fields_locators(container_locator)

        if field_name not in fields_locators:
            logger.debug(f"Field '{field_name}' not found in fields_locators")
            return False

        field_container = fields_locators[field_name]

        if not field_container.is_visible():
            logger.debug(f"Field '{field_name}' not visible")
            return False

        selected_chip = field_container.locator(".v-chip").first
        field_text = field_container.text_content() or ""
        has_text = bool(field_text.strip())
        has_chip = selected_chip.count() > 0 and selected_chip.is_visible()

        if not has_chip:
            input_field = field_container.locator("input").first
            if input_field.count() > 0:
                input_value = input_field.input_value() or ""
                has_input_value = bool(input_value.strip())
                logger.debug(f"Field '{field_name}' - has input value: {has_input_value}")
                has_text = has_text or has_input_value

        logger.debug(f"Field '{field_name}' - has chip: {has_chip}, has text: {has_text}")
        return has_chip or has_text

    def open_object_class_combobox(self) -> None:
        """Открывает выпадающий список combobox."""
        container_locator = self.page.locator(RackLocators.CREATE_RACK_FORM_CONTAINER)
        fields_locators = self.get_input_fields_locators(container_locator)
        combobox_container = fields_locators.get("Класс объекта учета")

        if not combobox_container:
            logger.error("Combobox 'Класс объекта учета' not found")
            return

        menu_selector = "div.v-menu__content.menuable__content__active"
        is_menu_open = self.page.locator(menu_selector).count() > 0

        if not is_menu_open:
            open_button = combobox_container.locator(SelectionBarLocators.OPEN_PARAMETERS_LIST_BUTTON)
            open_button.click(force=True, timeout=5000)
        else:
            logger.debug("Combobox menu is already open")

    def select_object_class(self, class_name: str) -> None:
        """
        Выбирает класс объекта из выпадающего списка.

        Args:
            class_name (str): Название класса объекта для выбора
        """
        logger.debug(f"Selecting object class: '{class_name}'...")
        self.open_object_class_combobox()
        self.selection_bar.select_value(class_name)
        self.wait_for_timeout(300)
        logger.debug(f"Object class '{class_name}' successfully selected")

    # Проверки:

    def check_field_error_highlighted(self, field_name: str) -> None:
        """
        Проверяет, что поле подсвечено цветом ошибки (валидация не пройдена).

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

        Raises:
            ValueError: Если поле не найдено в форме
            AssertionError: Если поле не подсвечено ошибкой
        """
        logger.debug(f"Checking field '{field_name}' for error highlighting...")
        assert self.is_field_highlighted_as_error(field_name), (
            f"Field '{field_name}' is not highlighted as error"
        )
        logger.debug(f"Field '{field_name}' is correctly highlighted with error color")

    def check_field_error_not_highlighted(self, field_name: str) -> None:
        """
        Проверяет, что поле НЕ подсвечено цветом ошибки (валидация успешна).

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

        Raises:
            ValueError: Если поле не найдено в форме
            AssertionError: Если поле подсвечено ошибкой
        """
        logger.debug(f"Checking field '{field_name}' for absence of error highlighting...")
        assert not self.is_field_highlighted_as_error(field_name), (
            f"Field '{field_name}' is incorrectly highlighted as error"
        )
        logger.debug(f"Field '{field_name}' correctly has no error highlighting")

    def check_object_class_selected(self, expected_class: str) -> None:
        """
        Проверяет что выбран указанный класс объекта.

        Args:
            expected_class (str): Ожидаемый выбранный класс объекта

        Raises:
            AssertionError: Если выбранный класс не соответствует ожидаемому
        """
        logger.debug(f"Checking selected object class: '{expected_class}'...")

        self.wait_for_timeout(500)
        actual_class = self.get_selected_object_class()

        is_match = (expected_class.lower() in actual_class.lower() or
                   actual_class.lower() in expected_class.lower())

        assert is_match, (
            f"Selected class does not match expected. "
            f"Expected: '{expected_class}', Got: '{actual_class}'"
        )

        logger.debug(f"Object class '{expected_class}' successfully selected (actual: '{actual_class}')")

    def check_toolbar_title(self, expected_title: str) -> None:
        """
        Проверяет заголовок тулбара.

        Args:
            expected_title (str): Ожидаемый заголовок тулбара

        Raises:
            AssertionError: Если заголовок не соответствует ожидаемому
        """
        logger.debug(f"Checking toolbar title: '{expected_title}'...")

        actual_text = self.toolbar.get_toolbar_title_text(
            filter_text="Создать дочерний элемент в"
        )

        assert expected_title in actual_text, (
            f"Title does not match. Expected: '{expected_title}', Got: '{actual_text}'"
        )

        logger.debug(f"Toolbar title is correct: '{actual_text}'")

    def should_be_toolbar_buttons(self) -> None:
        """
        Проверяет наличие и функциональность кнопок тулбара.
        """
        self.toolbar.check_button_visibility("add")
        self.toolbar.check_button_tooltip("add", "Добавить")
        self.toolbar.check_button_visibility("cancel")
        self.toolbar.check_button_tooltip("cancel", "Отменить")
        self.toolbar.click_button("cancel")
        self.wait_for_timeout(500)
