# makers/edit_rack_maker.py
"""Модуль для работы с модальным окном редактирования стойки."""

import re
from typing import Optional, List, Tuple, Any
from playwright.sync_api import Page
from tools.logger import get_logger
from locators.rack_locators import RackLocators
from components.modal_window_component import ModalWindowComponent
from components.dropdown_list_component import DropdownList
from components.confirm_component import ConfirmComponent
from elements.text_input_element import TextInput
from forms.edit_rack_form import EditRackForm, EditRackData


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


# Re-export EditRackData for backward compatibility
EditRackData = EditRackData
__all__ = ['EditRackMaker', 'EditRackData']

class EditRackMaker(ModalWindowComponent):
    """Компонент для работы с модальным окном редактирования стойки.

    Предоставляет методы для взаимодействия с элементами окна:
    - переключение между вкладками
    - заполнение полей общей информации (через EditRackForm)
    - работа с изображениями
    - настройка правил доступа
    - сохранение/отмена изменений
    - удаление стойки
    """

    # Константы для названий вкладок
    TAB_GENERAL = "Общая информация"
    TAB_IMAGE = "Изображение"
    TAB_SETTINGS = "Настройки"

    # Маппинг полей для вкладки "Настройки"
    ACCESS_RULES_MAPPING = {
        "Правила доступа для чтения": (
            "read_access_rules", "rules_read_input", "rules_read_list"
        ),
        "Правила доступа для записи": (
            "write_access_rules", "rules_write_input", "rules_write_list"
        ),
        "Правила доступа для получения СМС": (
            "sms_access_rules", "rules_sms_input", "rules_sms_list"
        ),
        "Правила доступа для получения email сообщения": (
            "email_access_rules", "rules_email_input", "rules_email_list"
        ),
        "Правила доступа для получения push уведомлений": (
            "push_access_rules", "rules_push_input", "rules_push_list"
        ),
    }

    # Локаторы для полей правил доступа
    ACCESS_RULES_LOCATORS = {
        "Правила доступа для чтения": RackLocators.SETTINGS_READ_RULES,
        "Правила доступа для записи": RackLocators.SETTINGS_WRITE_RULES,
        "Правила доступа для получения СМС": RackLocators.SETTINGS_SMS_RULES,
        "Правила доступа для получения email сообщения": RackLocators.SETTINGS_EMAIL_RULES,
        "Правила доступа для получения push уведомлений": RackLocators.SETTINGS_PUSH_RULES,
    }

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

        Args:
            page: Экземпляр страницы Playwright.
            rack_name: Имя редактируемой стойки.
        """

        super().__init__(page)
        self.rack_name = rack_name
        self.page = page
        self.active_tab = self.TAB_GENERAL
        self.tabs = {}
        self.content_items = {}
        self.delete_confirm = None
        self.edit_form = None

        # Настройка заголовка и кнопки закрытия
        self.window_title = rack_name
        locator_button_toolbar_close = (
            self.page.get_by_role("navigation")
            .filter(has_text=re.compile(self.window_title))
            .get_by_role("button")
        )

        self.add_toolbar_title(self.window_title)
        self.add_toolbar_button(locator_button_toolbar_close, "close")

        # Инициализация компонента подтверждения удаления
        self.delete_confirm = ConfirmComponent(page, " Отмена ", " Удалить ")

        # Инициализация вкладок и содержимого
        self._init_tabs()
        self._init_active_tab_content()
        self._init_toolbar_buttons()

    def _init_tabs(self) -> None:
        """Инициализирует вкладки окна редактирования."""

        self.tabs = {
            self.TAB_GENERAL: self.page.locator(RackLocators.MODAL_TAB_GENERAL),
            self.TAB_IMAGE: self.page.locator(RackLocators.MODAL_TAB_IMAGE),
            self.TAB_SETTINGS: self.page.locator(RackLocators.MODAL_TAB_SETTINGS),
        }
        logger.debug(f"Initialized tabs: {list(self.tabs.keys())}")

    def _init_active_tab_content(self) -> None:
        """Инициализирует содержимое активной вкладки."""

        self.content_items = {}

        if self.active_tab == self.TAB_GENERAL:
            self._init_general_tab_content()
        elif self.active_tab == self.TAB_IMAGE:
            self._init_image_tab_content()
        else:
            self._init_settings_tab_content()

    def _init_general_tab_content(self) -> None:
        """Инициализирует содержимое вкладки 'Общая информация'."""

        # Инициализируем форму редактирования
        self.edit_form = EditRackForm(self.page)
        # Копируем content_items из формы
        self.content_items.update(self.edit_form.content_items)
        logger.debug("General tab content initialized via EditRackForm")

    def _init_image_tab_content(self) -> None:
        """Инициализирует содержимое вкладки 'Изображение'."""

        try:
            self._init_image_upload_elements()
            logger.debug("Image tab content initialized")
        except Exception as e:
            logger.error(f"Error initializing image tab content: {e}")

    def _init_image_upload_elements(self) -> None:
        """Инициализирует элементы загрузки изображения."""

        image_tab_container = self.page.locator(RackLocators.IMAGE_UPLOAD_CONTAINER)
        upload_icon = image_tab_container.locator(RackLocators.IMAGE_UPLOAD_ICON)
        self.add_content_item("image_upload_icon", upload_icon)

        upload_input = image_tab_container.locator(RackLocators.IMAGE_UPLOAD_INPUT)
        self.add_content_item("image_upload_input", upload_input)

    def _init_settings_tab_content(self) -> None:
        """Инициализирует содержимое вкладки 'Настройки доступа'."""

        self._init_access_rules_fields()
        logger.debug("Settings tab content initialized")

    def _init_access_rules_fields(self) -> None:
        """Инициализирует поля правил доступа."""

        settings_container = self.page.locator(RackLocators.SETTINGS_CONTAINER)

        # Используем базовый метод для получения всех полей
        fields_locators = self.get_input_fields_locators(settings_container)

        # Для каждого поля из маппинга проверяем наличие и инициализируем
        for field_label, (_, input_name, list_name) in self.ACCESS_RULES_MAPPING.items():
            if field_label not in fields_locators:
                continue

            self._init_single_access_rule_field(
                field_label, fields_locators[field_label], input_name, list_name
            )

        logger.debug(
            f"Settings tab content initialized. Found fields: {list(fields_locators.keys())}"
        )

    def _init_single_access_rule_field(
        self, field_label: str, input_container: Any, input_name: str, list_name: str
    ) -> None:
        """Инициализирует одно поле правила доступа.

        Args:
            field_label: Метка поля.
            input_container: Контейнер поля ввода.
            input_name: Имя поля ввода.
            list_name: Имя списка.
        """

        try:
            # Ищем input внутри контейнера
            input_element = input_container.locator("input, textarea, select").first
            if input_element.count() > 0:
                field_input = TextInput(self.page, input_element, input_name)
                self.add_content_item(input_name, field_input)
                self.add_content_item(list_name, DropdownList(self.page))
                logger.debug(f"Initialized access rule field: '{field_label}'")
        except Exception as e:
            logger.error(f"Error initializing access rule field '{field_label}': {e}")

    def _init_toolbar_buttons(self) -> None:
        """Инициализирует кнопки тулбара."""

        self.add_button(self.page.locator(RackLocators.TOOLBAR_REPLACE_BUTTON), "replace")
        self.add_button(self.page.locator(RackLocators.TOOLBAR_DONE_BUTTON), "save")
        self.add_button(self.page.locator(RackLocators.TOOLBAR_CLOSE_BUTTON), "cancel")
        self.add_button(self.page.locator(RackLocators.TOOLBAR_REMOVE_BUTTON), "delete")

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

    def fill_rack_data(self, rack_data: EditRackData) -> dict:
        """Заполняет поля формы редактирования стойки.

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

        Returns:
            Словарь с результатами заполнения.
        """

        if self.active_tab != self.TAB_GENERAL:
            self.switch_to_tab(self.TAB_GENERAL)

        if not self.edit_form:
            logger.error("Edit form not initialized")
            return {
                "text_fields_filled": 0,
                "combobox_fields_filled": 0,
                "checkboxes_set": 0
            }

        results = self.edit_form.fill_rack_data(rack_data)
        logger.info(f"Filled rack data via EditRackForm: {results}")
        return results

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

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

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

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

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

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

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

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

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

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

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

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

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

        Raises:
            ValueError: Если указана неизвестная вкладка.
        """

        if tab_name not in self.tabs:
            raise ValueError(
                f"Unknown tab: {tab_name}. Available tabs: {list(self.tabs.keys())}"
            )

        self.tabs[tab_name].click()
        self.wait_for_timeout(1000)
        self.active_tab = tab_name
        self._init_active_tab_content()
        logger.info(f"Switched to tab: {tab_name}")

    def get_active_tab(self) -> str:
        """Возвращает название активной вкладки.

        Returns:
            Название активной вкладки.
        """
        return self.active_tab

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

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

        Returns:
            True если вкладка активна, иначе False.
        """
        return self.active_tab == tab_name

    # Действия с изображениями
    def upload_image(self, image_path: str) -> None:
        """Загружает изображение на вкладке 'Изображение'.

        Args:
            image_path: Путь к файлу изображения.

        Raises:
            RuntimeError: Если не найден элемент для загрузки изображения.
        """

        if self.active_tab != self.TAB_IMAGE:
            self.switch_to_tab(self.TAB_IMAGE)

        try:
            self._perform_image_upload(image_path)
        except Exception as e:
            logger.error(f"Error uploading image: {e}")
            raise

    def _perform_image_upload(self, image_path: str) -> None:
        """Выполняет загрузку изображения.

        Args:
            image_path: Путь к файлу изображения.

        Raises:
            RuntimeError: Если не найден элемент для загрузки изображения.
        """

        upload_icon = self.get_content_item("image_upload_icon")
        if upload_icon and upload_icon.count() > 0:
            upload_icon.click()
            self.wait_for_timeout(500)

        upload_input = self.get_content_item("image_upload_input")
        if upload_input and upload_input.count() > 0:
            upload_input.set_input_files(image_path)
            logger.info(f"Uploaded image: {image_path}")
            return

        # Пробуем найти input напрямую
        file_input = self.page.locator(RackLocators.IMAGE_UPLOAD_INPUT)
        if file_input.count() > 0:
            file_input.first.set_input_files(image_path)
            logger.info(f"Uploaded image via page input: {image_path}")
            return

        raise RuntimeError("Image upload input not found")

    def has_current_image(self) -> bool:
        """Проверяет, есть ли текущее изображение у стойки.

        Returns:
            True если изображение загружено, иначе False.
        """

        if self.active_tab != self.TAB_IMAGE:
            self.switch_to_tab(self.TAB_IMAGE)

        try:
            return self._check_image_exists()
        except Exception as e:
            logger.error(f"Error checking for current image: {e}")
            return False

    def _check_image_exists(self) -> bool:
        """Проверяет наличие изображения.

        Returns:
            True если изображение существует, иначе False.
        """

        image_container = self.page.locator(RackLocators.IMAGE_UPLOAD_CONTAINER)
        img_element = image_container.locator(RackLocators.IMAGE_PREVIEW)
        upload_icon = image_container.locator(RackLocators.IMAGE_UPLOAD_ICON)

        if img_element.count() > 0 and img_element.first.is_visible():
            return True

        return False

    # Действия с настройками доступа
    def fill_access_rules(
        self,
        users_to_add: Optional[List[str]] = None,
        target_fields: Optional[List[str]] = None
    ) -> dict:
        """Заполняет правила доступа в указанных полях.

        В каждый combobox добавляются указанные пользователи.

        Args:
            users_to_add: Список пользователей для добавления.
            target_fields: Список целевых полей для заполнения.

        Returns:
            Словарь с результатами заполнения.
        """

        if self.active_tab != self.TAB_SETTINGS:
            self.switch_to_tab(self.TAB_SETTINGS)

        results = self._init_fill_results()

        if users_to_add is None:
            users_to_add = self._get_default_users()

        fields_to_process = self._get_fields_to_process(target_fields)

        logger.info(f"Processing fields: {[f[0] for f in fields_to_process]}")
        logger.info(f"Users to add: {users_to_add}")

        for field_index, (field_label, _, input_name, _) in enumerate(fields_to_process):
            self._process_single_field(
                field_index, field_label, users_to_add, results
            )

        self._log_fill_summary(results, len(fields_to_process), len(users_to_add))

        return results

    def _init_fill_results(self) -> dict:
        """Инициализирует словарь результатов заполнения.

        Returns:
            Словарь с начальными значениями результатов.
        """

        return {
            "access_rules_filled": 0,
            "errors": [],
            "fields_processed": [],
            "field_stats": {}
        }

    def _get_default_users(self) -> List[str]:
        """Возвращает список пользователей по умолчанию.

        Returns:
            Список пользователей.
        """

        return [
            "admin",
            "manager",
            "operator",
            "sec",
            "collector"
        ]

    def _process_single_field(
        self,
        field_index: int,
        field_label: str,
        users_to_add: List[str],
        results: dict
    ) -> None:
        """Обрабатывает одно поле правил доступа.

        Args:
            field_index: Индекс поля.
            field_label: Название поля.
            users_to_add: Список пользователей для добавления.
            results: Словарь с результатами.
        """

        # Инициализируем статистику для поля
        results["field_stats"][field_label] = {
            "expected": len(users_to_add),
            "added": 0,
            "failed_users": []
        }

        field_locator = self.ACCESS_RULES_LOCATORS.get(field_label)
        if not field_locator:
            results["errors"].append(f"Locator not found for field '{field_label}'")
            return

        try:
            if field_index > 0:
                self.page.mouse.click(10, 10)
                self.wait_for_timeout(500)

            results["fields_processed"].append(field_label)

            # Находим элемент поля
            field_element = self.page.locator(field_locator).first
            if field_element.count() == 0:
                results["errors"].append(f"Field element not found for '{field_label}'")
                return

            self._clear_field(field_element)

            # Открываем combobox и добавляем пользователей
            added_count, field_errors = self._open_dropdown_and_add_users(
                field_element, field_label, users_to_add
            )

            results["access_rules_filled"] += added_count
            results["field_stats"][field_label]["added"] = added_count
            results["field_stats"][field_label]["failed_users"] = field_errors
            results["errors"].extend([f"{field_label}: {error}" for error in field_errors])

            # Закрываем dropdown
            self.page.mouse.click(10, 10)
            self.wait_for_timeout(500)

            logger.info(f"Field '{field_label}': added {added_count}/{len(users_to_add)} users")

        except Exception as e:
            results["errors"].append(f"Error processing field {field_label}: {str(e)}")

    def _get_fields_to_process(
        self,
        target_fields: Optional[List[str]] = None
    ) -> List[Tuple[str, str, str, str]]:
        """Определяет поля для обработки.

        Args:
            target_fields: Список целевых полей.

        Returns:
            Список кортежей (field_label, attr_name, input_name, list_name).
        """

        if target_fields is None:
            return list(self.ACCESS_RULES_MAPPING.items())

        fields_to_process = []
        for field_attr in target_fields:
            for field_label, (attr_name, input_name, list_name) in self.ACCESS_RULES_MAPPING.items():
                if attr_name == field_attr:
                    fields_to_process.append((field_label, attr_name, input_name, list_name))
                    break
        return fields_to_process

    def _clear_field(self, field_element: Any) -> None:
        """Очищает поле от выбранных значений.

        Args:
            field_element: Элемент поля для очистки.
        """

        parent_container = field_element.locator(
            "xpath=ancestor::div[contains(@class, 'v-input')]"
        ).first

        if parent_container.count() == 0:
            return

        clear_button = parent_container.locator(
            ".v-input__icon--clear button, .v-input__icon--append button, i.mdi-close-circle"
        ).first

        if clear_button.count() > 0 and clear_button.is_visible():
            clear_button.click()
            self.wait_for_timeout(500)

    def _open_dropdown_and_add_users(
        self,
        field_element: Any,
        field_label: str,
        users_to_add: List[str]
    ) -> Tuple[int, List[str]]:
        """Открывает выпадающий список и добавляет пользователей.

        Args:
            field_element: Элемент поля.
            field_label: Название поля.
            users_to_add: Список пользователей для добавления.

        Returns:
            Кортеж (количество добавленных, список ошибок).
        """

        added_count = 0
        errors = []

        field_element.click(force=True)
        self.wait_for_timeout(1500)

        dropdown_menu = self._get_dropdown_menu()
        if not dropdown_menu:
            errors.append(f"Could not open dropdown for {field_label}")
            return added_count, errors

        for username in users_to_add:
            added, error = self._add_user_to_dropdown(dropdown_menu, username, field_label)
            if added:
                added_count += 1
            if error:
                errors.append(error)

        return added_count, errors

    def _get_dropdown_menu(self) -> Any:
        """Возвращает выпадающее меню.

        Returns:
            Locator выпадающего меню или None, если меню не найдено.
        """

        dropdown_menu = self.page.locator(RackLocators.MENU_ACTIVE_RACK_FORM).first
        if dropdown_menu.count() == 0 or not dropdown_menu.is_visible():
            dropdown_menu = self.page.locator(
                ".v-menu__content--active, .menuable__content__active"
            ).first

        if dropdown_menu.count() == 0 or not dropdown_menu.is_visible():
            return None
        return dropdown_menu

    def _add_user_to_dropdown(
        self,
        dropdown_menu: Any,
        username: str,
        field_label: str
    ) -> Tuple[bool, Optional[str]]:
        """Добавляет пользователя из выпадающего списка.

        Args:
            dropdown_menu: Выпадающее меню.
            username: Имя пользователя.
            field_label: Название поля.

        Returns:
            Кортеж (добавлен ли пользователь, сообщение об ошибке или None).
        """

        try:
            user_item = dropdown_menu.locator(f"[role='listitem']:has-text('{username}')").first
            if user_item.count() == 0:
                user_item = dropdown_menu.locator(f"div:has-text('{username}')").first

            if user_item.count() > 0:
                user_item.click()
                self.wait_for_timeout(500)
                return True, None

            return False, f"User '{username}' not found in dropdown for {field_label}"
        except Exception as e:
            return False, f"Failed to add user '{username}' to {field_label}: {str(e)}"

    def _log_fill_summary(self, results: dict, fields_count: int, users_count: int) -> None:
        """Логирует итоговую статистику заполнения.

        Args:
            results: Словарь с результатами.
            fields_count: Количество полей.
            users_count: Количество пользователей.
        """

        total_expected = fields_count * users_count
        logger.info(f"Total added: {results['access_rules_filled']}/{total_expected}")

        for field_label, stats in results["field_stats"].items():
            if stats["added"] < stats["expected"]:
                logger.warning(
                    f"Field '{field_label}' added only {stats['added']}/{stats['expected']} users. "
                    f"Failed: {stats['failed_users']}"
                )

    def verify_access_rules(
        self,
        expected_users: Optional[List[str]] = None,
        target_fields: Optional[List[str]] = None
    ) -> dict:
        """Проверяет заполнение правил доступа в указанных полях.

        Проверяет, что в каждом поле есть все указанные пользователи.

        Args:
            expected_users: Список ожидаемых пользователей.
            target_fields: Список целевых полей для проверки.

        Returns:
            Словарь с результатами проверки.
        """

        if self.active_tab != self.TAB_SETTINGS:
            self.switch_to_tab(self.TAB_SETTINGS)

        if expected_users is None:
            expected_users = self._get_default_users()

        fields_to_verify = self._get_fields_to_process(target_fields)
        total_expected_fields = len(fields_to_verify) * len(expected_users)

        results = {
            "total_expected_fields": total_expected_fields,
            "correctly_filled": 0,
            "incorrectly_filled": 0,
            "field_errors": [],
            "fields_verified": [field_label for field_label, _, _, _ in fields_to_verify],
            "expected_users": expected_users
        }

        for field_label, _, _, _ in fields_to_verify:
            self._verify_single_field(field_label, expected_users, results)

        if results["total_expected_fields"] > 0:
            success_rate = results["correctly_filled"] / results["total_expected_fields"] * 100
            logger.info(
                f"Access rules verification: {results['correctly_filled']}/"
                f"{results['total_expected_fields']} ({success_rate:.1f}%)"
            )

        return results

    def _verify_single_field(
        self,
        field_label: str,
        expected_users: List[str],
        results: dict
    ) -> None:
        """Проверяет одно поле правил доступа.

        Args:
            field_label: Название поля.
            expected_users: Список ожидаемых пользователей.
            results: Словарь с результатами для обновления.
        """

        field_locator = self.ACCESS_RULES_LOCATORS.get(field_label)
        if not field_locator:
            self._add_field_error(
                results, field_label, expected_users,
                f"Locator not found for field '{field_label}'"
            )
            return

        try:
            field_element = self.page.locator(field_locator).first
            if field_element.count() == 0:
                self._add_field_error(
                    results, field_label, expected_users,
                    f"Field '{field_label}' not found"
                )
                return

            selected_users = self._get_selected_users(field_element)
            logger.debug(f"Field '{field_label}' selected users: {selected_users}")

            for expected_user in expected_users:
                if expected_user in selected_users:
                    results["correctly_filled"] += 1
                else:
                    results["incorrectly_filled"] += 1
                    results["field_errors"].append(
                        f"Field '{field_label}' missing user: {expected_user} "
                        f"(selected: {selected_users})"
                    )

        except Exception as e:
            self._add_field_error(
                results, field_label, expected_users,
                f"Error verifying {field_label}: {str(e)}"
            )
            logger.error(f"Error verifying {field_label}: {e}")

    def _get_selected_users(self, field_element: Any) -> List[str]:
        """Получает список выбранных пользователей из поля.

        Args:
            field_element: Элемент поля.

        Returns:
            Список выбранных пользователей.
        """

        selected_users = []
        parent_container = field_element.locator(
            "xpath=ancestor::div[contains(@class, 'v-input')]"
        ).first

        if parent_container.count() == 0:
            return selected_users

        selections_container = parent_container.locator(
            ".v-select__selections, .v-chip__content"
        ).first

        if selections_container.count() == 0:
            return selected_users

        user_elements = selections_container.locator(
            "span.v-chip__content, span.v-chip, span:not([class])"
        ).all()

        for element in user_elements:
            user_text = self._extract_user_text(element)
            if user_text:
                selected_users.append(user_text)

        return selected_users

    def _extract_user_text(self, element: Any) -> Optional[str]:
        """Извлекает текст пользователя из элемента.

        Args:
            element: Элемент DOM.

        Returns:
            Текст пользователя или None.
        """

        user_text = element.text_content() or ""
        user_text = user_text.strip()

        if not user_text or user_text in [",", " ", ""]:
            return None

        if user_text.startswith(','):
            user_text = user_text[1:].strip()

        return user_text if user_text else None

    def _add_field_error(
        self,
        results: dict,
        field_label: str,
        expected_users: List[str],
        error_msg: str
    ) -> None:
        """Добавляет ошибку для поля.

        Args:
            results: Словарь с результатами.
            field_label: Название поля (не используется, оставлен для единообразия).
            expected_users: Список ожидаемых пользователей.
            error_msg: Сообщение об ошибке.
        """

        for _ in expected_users:
            results["incorrectly_filled"] += 1
        results["field_errors"].append(error_msg)

    # Действия с кнопками
    def click_close_button(self) -> None:
        """Закрывает окно через кнопку 'Отменить'."""

        self.page.mouse.click(10, 10)
        self.wait_for_timeout(300)

        cancel_button = self.get_button_by_name("cancel")
        if cancel_button:
            cancel_button.click()
            logger.debug("Clicked close button")

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

        delete_button = self.get_button_by_name("delete")
        if not delete_button:
            return

        delete_button.click()
        logger.debug("Clicked remove button")
        self.wait_for_timeout(1500)

        self._confirm_deletion()

    def _confirm_deletion(self) -> None:
        """Подтверждает удаление стойки."""

        expected_title = "Удаление"
        try:
            self.delete_confirm.check_title(
                title=expected_title,
                msg=f"Expected title: '{expected_title}'"
            )
        except AssertionError as e:
            logger.warning(f"Dialog title mismatch: {e}")

        expected_message = f"Удалить {self.window_title}?"
        try:
            self.delete_confirm.check_text(
                text=expected_message,
                msg=f"Expected message: '{expected_message}'"
            )
        except AssertionError as e:
            logger.warning(f"Message text mismatch: {e}")

        self.delete_confirm.should_be_cancel_button()
        self.delete_confirm.should_be_allow_button()
        self.delete_confirm.click_allow_button()
        self.wait_for_timeout(2000)
        logger.debug("Remove confirmation completed")

    def click_done_button(self) -> None:
        """Сохраняет изменения стойки."""

        save_button = self.get_button_by_name("save")
        if save_button:
            save_button.click()
            logger.debug("Clicked done button")

    # Проверки
    def verify_all_filled_fields(
        self,
        rack_data: EditRackData,
        skip_fields: Optional[List[str]] = None
    ) -> dict:
        """Проверяет, что все поля заполнены корректно.

        Args:
            rack_data: Данные для проверки.
            skip_fields: Список полей, которые нужно пропустить.

        Returns:
            Словарь с результатами проверки.
        """

        if self.active_tab != self.TAB_GENERAL:
            self.switch_to_tab(self.TAB_GENERAL)

        results = {
            "total_expected_fields": 0,
            "correctly_filled": 0,
            "incorrectly_filled": 0,
            "not_filled": 0,
            "skipped_fields": 0,
            "field_errors": []
        }

        if skip_fields is None:
            skip_fields = []

        if not self.edit_form:
            logger.error("Edit form not initialized")
            results["field_errors"].append("Edit form not initialized")
            return results

        # Проверяем текстовые поля
        self._verify_text_fields(rack_data, skip_fields, results)

        # Проверяем combobox поля
        self._verify_combobox_fields(rack_data, skip_fields, results)

        # Проверяем чекбокс
        self._verify_checkbox(rack_data, skip_fields, results)

        if results["total_expected_fields"] > 0:
            success_rate = results["correctly_filled"] / results["total_expected_fields"] * 100
            logger.info(
                f"Field check: {results['correctly_filled']}/"
                f"{results['total_expected_fields']} ({success_rate:.1f}%)"
            )

        return results

    def _verify_text_fields(
        self,
        rack_data: EditRackData,
        skip_fields: List[str],
        results: dict
    ) -> None:
        """Проверяет текстовые поля.

        Args:
            rack_data: Данные для проверки.
            skip_fields: Список полей для пропуска.
            results: Словарь с результатами для обновления.
        """

        for field_label, (attr_name, field_name) in self.edit_form.TEXT_FIELDS_MAPPING.items():
            expected_value = getattr(rack_data, attr_name, "")
            if not expected_value or not str(expected_value).strip():
                continue

            results["total_expected_fields"] += 1

            if field_label in skip_fields:
                results["skipped_fields"] += 1
                continue

            self._verify_single_text_field(field_label, field_name, expected_value, results)

    def _verify_single_text_field(
        self,
        field_label: str,
        field_name: str,
        expected_value: str,
        results: dict
    ) -> None:
        """Проверяет одно текстовое поле.

        Args:
            field_label: Метка поля.
            field_name: Имя поля.
            expected_value: Ожидаемое значение.
            results: Словарь с результатами.
        """

        try:
            input_field = self.edit_form.get_content_item(field_name)
            if not input_field:
                results["not_filled"] += 1
                results["field_errors"].append(f"Field '{field_label}' input not found")
                return

            actual_value = input_field.get_input_value()
            if actual_value == expected_value:
                results["correctly_filled"] += 1
            else:
                results["incorrectly_filled"] += 1
                results["field_errors"].append(
                    f"Field '{field_label}': expected '{expected_value}', got '{actual_value}'"
                )
        except Exception as e:
            results["not_filled"] += 1
            results["field_errors"].append(f"Error checking field '{field_label}': {str(e)}")

    def _verify_combobox_fields(
        self,
        rack_data: EditRackData,
        skip_fields: List[str],
        results: dict
    ) -> None:
        """Проверяет combobox поля.

        Args:
            rack_data: Данные для проверки.
            skip_fields: Список полей для пропуска.
            results: Словарь с результатами для обновления.
        """

        for field_label, (attr_name, _, _) in self.edit_form.COMBOBOX_FIELDS_MAPPING.items():
            expected_value = getattr(rack_data, attr_name, "")
            if not expected_value or not str(expected_value).strip():
                continue

            results["total_expected_fields"] += 1

            if field_label in skip_fields:
                results["skipped_fields"] += 1
                continue

            self._verify_single_combobox_field(field_label, expected_value, results)

    def _verify_single_combobox_field(
        self,
        field_label: str,
        expected_value: str,
        results: dict
    ) -> None:
        """Проверяет одно combobox поле.

        Args:
            field_label: Метка поля.
            expected_value: Ожидаемое значение.
            results: Словарь с результатами.
        """

        try:
            actual_value = self.edit_form.get_field_value(field_label) or ""
            actual_clean = actual_value.strip()
            expected_clean = expected_value.strip()

            if actual_clean == expected_clean:
                results["correctly_filled"] += 1
            else:
                results["incorrectly_filled"] += 1
                results["field_errors"].append(
                    f"Combobox '{field_label}': expected '{expected_clean}', got '{actual_clean}'"
                )
        except Exception as e:
            results["not_filled"] += 1
            results["field_errors"].append(f"Error checking combobox '{field_label}': {e}")

    def _verify_checkbox(
        self,
        rack_data: EditRackData,
        skip_fields: List[str],
        results: dict
    ) -> None:
        """Проверяет чекбокс.

        Args:
            rack_data: Данные для проверки.
            skip_fields: Список полей для пропуска.
            results: Словарь с результатами для обновления.
        """

        if rack_data.ventilation_panel is None:
            return

        results["total_expected_fields"] += 1

        if "Вентиляционная панель" in skip_fields:
            results["skipped_fields"] += 1
            return

        try:
            checkbox = self.edit_form.get_content_item("ventilation_checkbox")
            if not checkbox:
                results["not_filled"] += 1
                results["field_errors"].append("Checkbox 'Ventilation panel' not found")
                return

            checkbox_state = checkbox.is_checked()
            if checkbox_state == rack_data.ventilation_panel:
                results["correctly_filled"] += 1
            else:
                results["incorrectly_filled"] += 1
                expected_status = "enabled" if rack_data.ventilation_panel else "disabled"
                actual_status = "enabled" if checkbox_state else "disabled"
                results["field_errors"].append(
                    f"Checkbox 'Ventilation panel': expected '{expected_status}', "
                    f"got '{actual_status}'"
                )
        except Exception as e:
            results["not_filled"] += 1
            results["field_errors"].append(f"Error checking checkbox: {str(e)}")