"""Модуль dropdown_list_component содержит класс для работы с выпадающими списками.

Класс DropdownList наследует базовый функционал BaseComponent и добавляет
методы для взаимодействия с выпадающими списками на странице.
"""
import re
from playwright.sync_api import Page, Locator
from tools.logger import get_logger
from components.base_component import BaseComponent

logger = get_logger("DROPDOWN_LIST")

class DropdownList(BaseComponent):
    """Класс для работы с выпадающими списками.

    Наследует функциональность BaseElement и добавляет специфичные
    методы для выбора и проверки элементов списка.
    """

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

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

        super().__init__(page)

    # Действия:
    def click_item_with_text(self, text: str) -> None:
        """Выбирает элемент списка по указанному тексту.

        Args:
            text (str): Текст элемента для выбора.
        """

        element = self.page.get_by_role("listitem").filter(has_text=text)
        if element.count() > 1:
            rtext = f"^{text}$"
            element = self.page.get_by_role("listitem").filter(
                has_text=re.compile(rtext)
            )
        element.click()

    def get_combobox_options(self, combobox_locator: str | Locator,
                            listbox_locator: str | Locator,
                            icon_locator: str | Locator = None) -> list[str]:
        """
        Получает список доступных опций из combobox.

        Args:
            combobox_locator: Локатор combobox
            listbox_locator: Локатор выпадающего списка
            icon_locator: Локатор иконки для клика (опционально)

        Returns:
            list[str]: Список доступных опций
        """
        logger.info("Getting combobox options list...")

        # Открываем combobox (если еще не открыт)
        self.open_combobox(combobox_locator, listbox_locator, icon_locator)

        options_list = self.get_item_names(listbox_locator)

        # Закрываем combobox (кликаем вне его)
        self.page.mouse.click(10, 10)
        self.page.wait_for_timeout(500)

        logger.info(f"Found options: {len(options_list)} - {options_list}")
        return options_list

    def get_item_names(self, locator: str | Locator) -> list[str]:
        """Возвращает тексты всех элементов по указанному локатору.

        Args:
            locator: Локатор элементов или строка с CSS/XPath.

        Returns:
            Список текстов элементов.
        """

        loc = self.get_locator(locator)
        texts = loc.all_inner_texts()
        return texts[0].splitlines()

    def get_selected_combobox_value(self, combobox_locator: str | Locator,
                                   value_locator: str | Locator = None) -> str:
        """
        Получает выбранное значение из combobox.

        Args:
            combobox_locator: Локатор combobox
            value_locator: Локатор элемента с выбранным значением (опционально)

        Returns:
            str: Выбранное значение или пустая строка если ничего не выбрано
        """
        combobox = self.get_locator(combobox_locator)

        selected_value = ""

        if value_locator:
            # Используем переданный локатор для значения
            value_element = combobox.locator(value_locator)
            if value_element.count() > 0:
                selected_value = value_element.first.text_content().strip()
        else:
            # Ищем в span элементах по умолчанию
            span_locator = combobox.locator("span")
            if span_locator.count() > 0:
                for i in range(span_locator.count()):
                    span_text = span_locator.nth(i).text_content().strip()
                    if span_text and span_text not in ["Класс объекта учета"]:
                        selected_value = span_text
                        break

        logger.info(f"Selected combobox value: '{selected_value}'")
        return selected_value

    def open_combobox(self, combobox_locator: str | Locator,
                     listbox_locator: str | Locator,
                     icon_locator: str | Locator = None) -> None:
        """
        Открывает выпадающий список combobox.

        Args:
            combobox_locator: Локатор combobox
            listbox_locator: Локатор выпадающего списка
            icon_locator: Локатор иконки для клика (опционально)
        """
        logger.info("Opening combobox...")

        combobox = self.get_locator(combobox_locator)
        listbox = self.get_locator(listbox_locator)

        # Прокручиваем до combobox
        combobox.scroll_into_view_if_needed()
        self.page.wait_for_timeout(1000)

        # Проверяем, не открыт ли уже список
        listbox_already_open = False
        listbox_count = listbox.count()

        if listbox_count > 0:
            listbox_already_open = listbox.first.is_visible()

        if not listbox_already_open:
            # Если указан локатор иконки, кликаем на него, иначе на сам combobox
            if icon_locator:
                icon = combobox.locator(icon_locator)
                icon.scroll_into_view_if_needed()
                icon.click(timeout=10000)
            else:
                combobox.click(timeout=10000)
            logger.info("Combobox click completed")
            self.page.wait_for_timeout(1000)

        # Проверяем что список открылся
        listbox_count_after = listbox.count()
        listbox_visible = False

        if listbox_count_after > 0:
            listbox_visible = listbox.first.is_visible()

        if listbox_visible:
            logger.info("Dropdown list found and opened")
        else:
            logger.warning("Failed to open dropdown list")

    def scroll_until_end(self, locator: str | Locator) -> None:
        """
        Скроллит список до тех пор, пока не перестанут подгружаться новые элементы.

        Args:
            locator: Локатор элементов или строка с CSS/XPath.
        """

        loc = self.get_locator(locator)

        items_count = 0
        attempts = 0
        max_attempts = 3
        last_item_name = ""

        while attempts < max_attempts:
            self.page.wait_for_timeout(300)

            item_names = self.get_item_names(loc)
            current_count = len(item_names)

            if current_count == items_count:
                attempts += 1
            else:
                items_count = current_count
                attempts = 0

            last_item_name = item_names[current_count-1]
            element = self.page.get_by_role("listitem").filter(
                has_text=last_item_name
            )
            element.scroll_into_view_if_needed()

        self.page.wait_for_timeout(300)
        self.check_item_with_text(last_item_name)

    # Проверки:
    def check_item_with_text(self, text: str) -> None:
        """Проверяет наличие и доступность элемента списка.

        Args:
            text (str): Текст элемента для проверки.

        Raises:
            AssertionError: Если элемент отсутствует или недоступен.
        """

        element = self.page.get_by_role("listitem").filter(has_text=text)
        if element.count() > 1:
            rtext = f"^{text}$"
            element = self.page.get_by_role("listitem").filter(
                has_text=re.compile(rtext)
            )
        enabled = element.is_enabled()
        if not enabled:
            assert False, f"Dropdown list item '{text}' is missing or disabled"

    def check_vertical_scrolling(self, locator: str | Locator) -> bool:
        """
        Проверяет функцию вертикального скроллинга списка.

        Args:
            locator: Локатор элементов или строка с CSS/XPath.

        Returns:
            True или False значение в зависимости от скроллируемый список или нет.
        """

        loc = self.get_locator(locator)

        is_scrollable_vertically = self.is_scrollable_vertically(loc)
        if  is_scrollable_vertically:
            self.scroll_until_end(loc)

            item_names = self.get_item_names(loc)
            first_item_name = item_names[0]

            self.scroll_up(loc)
            self.page.wait_for_timeout(300)
            self.check_item_with_text(first_item_name)

        return is_scrollable_vertically
