"""Модуль вкладки 'Сеансы/Текущие'.

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

from playwright.sync_api import Page, Locator
from locators.table_locators import TableLocators
from locators.button_locators import ButtonLocators
from elements.tooltip_button_element import TooltipButton
from data.roles_dict import roles_dict
from data.environment import host
from components.toolbar_component import ToolbarComponent
from components.table_component import TableComponent
from components.confirm_component import ConfirmComponent
from pages.base_page import BasePage

class CurrentSessionsTab(BasePage):
    """Класс для работы с вкладкой 'Сеансы/Текущие'.

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

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

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

        super().__init__(page)

        self.toolbar = ToolbarComponent(page, "Сеансы")
        self.sessions_table = TableComponent(page)

        self.delete_session_confirm = ConfirmComponent(page, " Отмена ", " Удалить ")

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

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

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

        return self.sessions_table.get_rows_count(TableLocators.TABLE_WORK_AREA)

    def get_delete_session_button_from_row(self, row_index: int) -> TooltipButton:
        """Возвращает кнопку удаления сеанса для указанной строки.

        Args:
            row_index: Индекс строки в таблице.

        Returns:
            TooltipButton: Кнопка с подсказкой.

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

        row_locator = self.sessions_table.get_row_locator(
            TableLocators.TABLE_WORK_AREA,
            row_index
        )
        assert isinstance(row_locator, Locator), f"Row with index {row_index} is missing"

        button_locator = row_locator.locator(ButtonLocators.BUTTON_DELETE_SESSION)
        return TooltipButton(self.page, button_locator, "delete_session_button")

    def get_session_token(self) -> str:
        """Возвращает токен текущего пользователя.

        Args:

        Returns:
            str: Токен текущего пользователя

        Raises:
        """
        return host.get_access_token()

    def find_session_in_table(self, token: str) -> int:
        """Ищет сеанс пользователя в таблице по выданному ему токену.

        Args:
            token (str): Токен пользователя

        Returns:
            int: Индекс строки или -1 если не найден

        Raises:
            AssertionError: Если таблица пуста.
        """
        table_content = self.sessions_table.read(TableLocators.TABLE_WORK_AREA)
        if len(table_content) == 0:
            assert False, "The contents of the table are missing"

        del table_content[0]  # Удаляем заголовок

        for row_index, session_info in enumerate(table_content):
            if token in session_info:
                return row_index
        return -1

    def delete_session_by_token(self, token: str) -> None:
        """Удаляет сеанс по токену.

        Args:
            token (str): Токен сеанс для удаления

        Raises:
            AssertionError: Если сеанс не найден или удаление не удалось.
        """
        row_index = self.find_session_in_table(token)
        if row_index == -1:
            raise AssertionError(f"Session with token {token} not found")

        self.delete_session_by_index(row_index)

    def delete_session_by_index(self, row_index: int) -> None:
        """Удаляет сеанс по индексу строки.

        Args:
            row_index (int): Индекс строки в таблице

        Raises:
            AssertionError: Если удаление не удалось.
        """
        try:
            # Находим кнопку удаления сеанса и нажимаем на нее
            delete_session_button = self.get_delete_session_button_from_row(row_index)
            delete_session_button.click()
            self.page.wait_for_timeout(1000)

            # Подтверждаем удаление
            self.delete_session_confirm.click_allow_button()

            # Ждем обновления таблицы
            self.page.wait_for_timeout(1000)

        except Exception as e:
            raise AssertionError(f"Failed to delete session at index {row_index}: {e}")


    def scroll_sessions_table_up(self) -> None:
        """Прокручивает таблицу сеансов вверх."""

        self.sessions_table.scroll_up(TableLocators.TABLE_SCROLL_CONTAINER)

    def scroll_sessions_table_down(self) -> None:
        """Прокручивает таблицу сеансов вниз."""

        self.sessions_table.scroll_down(TableLocators.TABLE_SCROLL_CONTAINER)

    # Проверки:
    def check_delete_session_confirm_window(self):
        """ Проверяет контент и возможность горизонтального скроллинга окна подтверждения удаления сеанс. """

        # Поиск в таблице сеанс сроки для текущего пользователя
        session_token = self.get_session_token()
        row_index = self.find_session_in_table(session_token)
        if row_index == -1:
            assert False, "Session for this token has not been found"

        # Найти кнопку удаления сеанса и нажать на нее
        delete_session_button = self.get_delete_session_button_from_row(row_index)
        delete_session_button.click()

        # Проверка открытия окна подтверждения с заголовком "Удаление"
        title = "Удаление"
        self.delete_session_confirm.check_title(
            title,
            f"Confirmation dialog window text '{title}' is missing"
        )

        # Проверка текста в окне подтверждения
        confirm_message = f"Удалить сеанс {session_token}?"
        self.delete_session_confirm.check_text(
            confirm_message,
            "Confirmation dialog window text does not match what is expected"
        )

        # Проверка наличия и видимости кнопки "Отмена"
        self.delete_session_confirm.should_be_cancel_button()

        # Проверка наличия и видимости кнопки "Удалить"
        self.delete_session_confirm.should_be_allow_button()

        # Проверка текста на кнопках
        self.delete_session_confirm.check_cancel_button_text(" Отмена ")
        self.delete_session_confirm.check_allow_button_text(" Удалить ")

        # Проверка горизонтального скроллинга
        is_scrollable_horizontally = self.delete_session_confirm.check_window_horizontal_scrolling()
        assert is_scrollable_horizontally, "Should be horizontal scrolling"

        self.delete_session_confirm.scroll_window_right()
        self.page.wait_for_timeout(3000)
        self.delete_session_confirm.scroll_window_left()
        self.page.wait_for_timeout(2000)

        # Нажать кнопку "Отмена"
        self.delete_session_confirm.click_cancel_button()

    def check_sessions_table_content(self, verify: bool = False) -> None:
        """Проверяет содержимое таблицы сеансов.

        Args:
            verify: Проверять соответствие данных из БД. По умолчанию False.

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

        expected_headers = [
            'ID сеанса',
            'ID пользователя',
            'Время жизни',
            'Роль',
            'Адрес'
        ]


        table_content = self.sessions_table.read(TableLocators.TABLE_WORK_AREA)
        len_table_content = len(table_content)

        if len_table_content == 0:
            assert False, "The contents of the table are missing"

        actual_headers = table_content[0]

        self.check_equals(
            actual_headers,
            expected_headers,
            f"Expected table headers {expected_headers} are not equal {actual_headers}"
        )

        if len_table_content == 1:
            assert False, "Table body is missing"

        if verify:
            self.verify_sessions_table_content(table_content)

        for index in range(len_table_content - 1):
            self.should_be_delete_button_on_sessions_table_row(index, "Удалить")

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

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

        return self.sessions_table.is_scrollable_vertically(
            TableLocators.TABLE_SCROLL_CONTAINER
        )

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

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

        self.sessions_table.check_first_row_visibility(TableLocators.TABLE_WORK_AREA)

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

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

        self.sessions_table.check_last_row_visibility(TableLocators.TABLE_WORK_AREA)

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

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

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

        self.sessions_table.check_row_highlighting(
            TableLocators.TABLE_WORK_AREA,
            row_index
        )

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

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

        self.toolbar.check_toolbar_presence("Toolbar is missing")

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

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

        self.sessions_table.check_visibility(
            TableLocators.TABLE_WORK_AREA,
            "Sessions table is missing"
        )

    def should_be_delete_button_on_sessions_table_row(
        self,
        row_index: int,
        tooltip: str
    ) -> None:
        """Проверяет наличие кнопки удаления в строке таблицы.

        Args:
            row_index: Индекс проверяемой строки.
            tooltip: Ожидаемый текст подсказки.

        Raises:
            AssertionError: Если кнопка отсутствует или подсказка неверна.
        """
        delete_button = self.get_delete_session_button_from_row(row_index)

        # Ожидаем исчезновения предыдущих подсказок перед проверкой
        delete_button.wait_for_tooltip_to_disappear()

        delete_button.check_visibility(
            f"Delete session button is missing on {row_index} row"
        )
        delete_button.check_tooltip_with_text(tooltip)

        # Ожидаем исчезновения подсказки после проверки
        delete_button.wait_for_tooltip_to_disappear()


    def should_be_session_in_table(self, token: str) -> None:
        """Проверяет наличие сеанса пользователя в таблице.

        Args:
            token (str): Токен пользователя

        Raises:
            AssertionError: Если сеанс не найден.
        """
        found = self.find_session_in_table(token)
        if found == -1:
            assert False, "Session for this token has not been found"

    def should_not_be_session_in_table(self, token: str) -> None:
        """Проверяет отсутствие сеанса пользователя в таблице.

        Args:
            token (str): Токен пользователя

        Raises:
            AssertionError: Если сеанс найден.
        """
        found = self.find_session_in_table(token)
        if found != -1:
            assert False, "Session for this token has been found"


    def verify_sessions_table_content(self, sessions_table: list) -> None:
        """Сверяет данные таблицы с данными из БД.

        Args:
            sessions_table: Данные из таблицы на странице.

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

        expected_sessions_list = []

        # Отправка запроса к бэкенду для получения информации о сеансах
        response = self.send_get_api_request("e-nms/auth/sessions")
        response_body = self.get_response_body(response)

        for item in response_body:
            session_info = []
            session_info.append(item["id"])
            session_info.append(item["userId"])

            # Временно неподдерживаемое поле: время жизни сеанса
            session_info.append("")

            roles = []
            for role in item["roles"]:
                if role in roles_dict.keys():
                    roles.append(roles_dict[role])

            session_info.append(",".join(roles))
            session_info.append(item["ip"])

            expected_sessions_list.append(session_info)

        del sessions_table[0]  # Удаляем заголовок

        self.check_lists_equals(
            sessions_table,
            expected_sessions_list,
            "Actual sessions list is not equal expected users list on base db"
        )
