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

Содержит класс ServiceStatusTab для работы с таблицей сервисов.
Позволяет проверять состояние и взаимодействовать с элементами вкладки.
"""

import math
from playwright.sync_api import Page, Locator, expect
from elements.text_element import Text
from elements.button_element import Button
from components.table_component import TableComponent
from pages.base_page import BasePage


class ServiceStatusTab(BasePage):
    """Класс для работы с вкладкой 'Статус компонентов'.

    Предоставляет методы для взаимодействия с таблицей сервисов и проверки
    её состояния.

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

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

        super().__init__(page)

        self.iframe_container_locator = page.locator("div.container.iframe-wrapper")
        self.iframe_locator = page.frame_locator("//iframe[@class='iframe-class']")
        self.table_locator = self.iframe_locator.locator("div.MuiBox-root > div > table")
        self.tab_title_locator = self.iframe_locator.locator("//h5[text()='Состояние контейнеров']")
        self.update_button_locator = self.iframe_locator.get_by_role("button", name='Обновить')

        self.tab_title = Text(page,
                              self.tab_title_locator,
                              "tab_title")
        self.update_button = Button(page,
                                    self.update_button_locator,
                                    "update_button")

        self.services_table = TableComponent(page)

    # Действия:
    def calculate_coordinates(self, locator: Locator) -> dict:
        """Вычисление координат элемента для манипуляции с ним мышкой"""

        coordinates = {}

        offsets_scales = self.get_offsets_scales()

        bounding_box = locator.evaluate("el => el.getBoundingClientRect()")
        assert bounding_box, "Required element is not visible"

        offset_x = offsets_scales["offset_x"]
        offset_y = offsets_scales["offset_y"]
        scale_x = offsets_scales["scale_x"]
        scale_y = offsets_scales["scale_y"]

        coordinates["center_x"] = (bounding_box["x"] + bounding_box["width"] / 2) * scale_x + offset_x
        coordinates["center_y"] = (bounding_box["y"] + bounding_box["height"] / 2) * scale_y + offset_y
        return coordinates

    def get_offsets_scales(self) -> dict:
        """Возвращает словарь, содержащий смещения контейнера фрейма и его коэффициенты"""

        offsets_scales = {}

        iframe_container_bounding_box = self.iframe_container_locator.\
                                        evaluate("el => el.getBoundingClientRect()")
        assert iframe_container_bounding_box, "Iframe container is not visible"

        iframe_bounding_box = self.iframe_locator.locator("div#root > div"). \
                              evaluate("el => el.getBoundingClientRect()")
        assert iframe_bounding_box, "Iframe content is not visible"

        offsets_scales["offset_x"] = iframe_container_bounding_box["x"]
        offsets_scales["offset_y"] = iframe_container_bounding_box["y"]
        offsets_scales["scale_x"] = iframe_container_bounding_box["width"]/iframe_bounding_box["width"]
        offsets_scales["scale_y"] = iframe_container_bounding_box["height"]/iframe_bounding_box["height"]

        return offsets_scales

    def datetime2timestamp(self, date_column: str) -> list[float]:
        """ Конвертация строкового представления даты и времени в Unix timestamp
        """

        converted = []

        for date in date_column:
            timestamp = self.services_table.datetime2timestamp(date,format_string="%d-%m-%y %H:%M:%S")
            assert timestamp, f"Error conversation to timestamp for {date}"
            converted.append(timestamp)

        return converted

    def click_update_button(self) -> None:
        """Нажатие кнопки 'Обновить'"""

        coordinates = self.calculate_coordinates(self.update_button_locator)
        self.page.mouse.click(math.ceil(coordinates["center_x"]),
                              math.ceil(coordinates["center_y"]), delay=300)

    def get_column(self, index: int) -> list[str]:
        """Возвращает столбец таблицы по индексу.

        Returns:
            list[str]: Столбец таблицы по индексу.

        Raises:
            AssertionError: Если таблица пуста или столбца с таким индексом в таблице нет.
        """

        return self.services_table.get_column(self.table_locator, index)

    def get_rows_count(self) -> int:
        """Возвращает количество строк в таблице (без заголовка).

        Returns:
            int: Количество строк с данными.

        Raises:
            AssertionError: Если таблица пуста.
        """

        return self.services_table.get_rows_count(self.table_locator)

    def get_workarea_widht(self) -> float:
        """Возвращает текущую ширину рабочей области вкладки."""

        iframe_container_bounding_box = self.iframe_container_locator.evaluate("el => el.getBoundingClientRect()")
        return iframe_container_bounding_box["width"]

    def scroll_services_tab_up(self) -> None:
        """Прокручивает содержимое вкладки вверх."""

        self.tab_title_locator.scroll_into_view_if_needed()

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

        nrows = self.get_rows_count()
        last_row = self.services_table.get_row_locator(self.table_locator, nrows-1)
        last_row.scroll_into_view_if_needed()

   # Проверки:
    def check_services_table_content(self) -> None:
        """Проверяет содержимое таблицы сервисов.

        Проверяет заголовки и наличие данных в таблице.

        Raises:
            AssertionError: Если таблица пуста или заголовки неверны.
        """

        expected_headers = [
            'СТЕК',
            'КОНТЕЙНЕР',
            'ТЭГ',
            'СТАТУС',
            'ВРЕМЯ СОЗДАНИЯ',
            'ЦЕЛОСТНОСТЬ',
            'ДЕЙСТВИЯ'
        ]

        self.services_table.check_content(self.table_locator, expected_headers)

        # Проверяем наличие кнопок и тултипов в последней ячейке строки
        rows_count = self.services_table.get_rows_count(self.table_locator)
        for i in range(rows_count):
            row_locator = self.services_table.get_row_locator(self.table_locator, i)
            row_locator.scroll_into_view_if_needed()

            layers_button = row_locator.get_by_role("button", name="Слои")
            expect(layers_button).to_be_visible(), f"Layers button is missing in {i} row"
            self.check_tooltip(layers_button, "Слои")

            lounch_button = row_locator.get_by_role("button", name="Запуск", exact=True)
            expect(lounch_button).to_be_visible(), f"Lounch button is missing in {i} row"
            self.check_tooltip(lounch_button, "Запуск")

            stop_button = row_locator.get_by_role("button", name="Остановка")
            expect(stop_button).to_be_visible(), f"Stop button is missing in {i} row"
            self.check_tooltip(stop_button, "Остановка")

            restart_button = row_locator.get_by_role("button", name="Перезапуск", exact=True)
            expect(restart_button).to_be_visible(), f"Restart button is missing in {i} row"
            self.check_tooltip(restart_button, "Перезапуск")


    def check_tooltip(self, button_locator: Locator, expected_text: str) -> None:
        """Проверка текста тултипа кнопки в последней ячейке строки"""

        # Наведение на элемент для отображения подсказки
        coordinates = self.calculate_coordinates(button_locator)

        self.page.mouse.move(math.ceil(coordinates["center_x"]),
                             math.ceil(coordinates["center_y"]), steps=3)

        # Получение элемента подсказки и ее текста
        tooltip = self.iframe_locator.get_by_role("tooltip").locator("div.MuiTooltip-tooltip").first
        tooltip.wait_for(state="visible", timeout=5000)

        actual_text = tooltip.text_content().strip()
        assert expected_text==actual_text, f"Should be tooltip with text: {expected_text}, got: {actual_text}"

    def check_services_table_verticall_scrolling(self) -> bool:
        """Проверяет возможность вертикальной прокрутки таблицы.

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

        loc = self.iframe_locator.locator("div.MuiBox-root > div > div").first
        return loc.evaluate("el => el.scrollHeight > el.clientHeight")

    def check_services_tab_title_visibility(self) -> None:
        """Проверяет видимость заголовка вкладки.

        Raises:
            AssertionError: Если строка не видна.
        """

        self.tab_title.check_visibility("The services tab title is not visible")

    # def check_services_table_first_row_visibility(self) -> None:
    #     """Проверяет видимость первой строки таблицы.

    #     Raises:
    #         AssertionError: Если строка не видна.
    #     """

    #     self.services_table.check_first_row_visibility(self.table_locator)

    def check_services_table_last_row_visibility(self) -> None:
        """Проверяет видимость последней строки таблицы.

        Raises:
            AssertionError: Если строка не видна.
        """

        self.services_table.check_last_row_visibility(self.table_locator)

    def check_services_table_row_highlighting(self, row_index: int) -> None:
        """Проверяет выделение указанной строки таблицы.

        Args:
            row_index: Индекс проверяемой строки.

        Raises:
            AssertionError: Если строка не выделена.
        """

        # offsets_scales = self.get_offsets_scales()

        self.services_table.check_mui_table_row_highlighting(
            self.table_locator,
            row_index)

    def should_be_tab_title(self) -> None:
        """Проверяет наличие заголовка вкладки.

        Raises:
            AssertionError: Если заголовок отсутствует.
        """

        self.tab_title.check_visibility(
            "Title of service statuses tab is missing"
        )

    def should_be_services_table(self) -> None:
        """Проверяет наличие таблицы сервисов.

        Raises:
            AssertionError: Если таблица отсутствует.
        """

        self.services_table.check_visibility(
            self.table_locator,
            "Service statuses table is missing"
        )

    def should_be_update_button(self) -> None:
        """Проверяет наличие кнопки 'Обновить'.

        Raises:
            AssertionError: Если кнопка отсутствует.
        """

        self.update_button.check_visibility(
            "Update button on top of service statuses tab is missing"
        )
