"""Модуль вкладки 'Пользователи'.

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

import re
from playwright.sync_api import Page
from locators.table_locators import TableLocators
from components_derived.modal_edit_user import EditUserModalWindow
from components_derived.modal_add_local_user import AddLocalUserModalWindow
from components_derived.modal_add_AD_user import AddADUserModalWindow
from data.roles_dict import roles_dict
from components.toolbar_component import ToolbarComponent
from components.table_component import TableComponent
from components.modal_window_component import ModalWindowComponent
from components.alert_component import AlertComponent
from pages.base_page import BasePage


class UsersTab(BasePage):
    """Класс для работы с вкладкой 'Пользователи'.

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

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

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

        super().__init__(page)

        locator_button_1 = self.page.get_by_role("navigation").filter(
            has_text=re.compile("Пользователи")
        ).get_by_role("button").nth(0)
        locator_button_2 = self.page.get_by_role("navigation").filter(
            has_text=re.compile("Пользователи")
        ).get_by_role("button").nth(1)

        self.toolbar = ToolbarComponent(page, "Пользователи")
        self.toolbar.add_tooltip_button(locator_button_1, "edit")
        self.toolbar.add_tooltip_button(locator_button_1, "add_user")
        self.toolbar.add_tooltip_button(locator_button_2, "close")

        self.users_table = TableComponent(page)
        self.modal_windows = {}
        self.alert = AlertComponent(page)

    # Действия:

    def add_modal_window(self, window_type: str, title: str) -> None:
        """Добавляет модальное окно в коллекцию.

        Args:
            window_type: Тип окна ('add_user' или 'edit_user').
            title: Заголовок окна.

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

        if window_type == "add_local_user":
            self.modal_windows["add_local_user"] = AddLocalUserModalWindow(self.page)
        elif window_type == "add_AD_user":
            self.modal_windows["add_AD_user"] = AddADUserModalWindow(self.page)
        elif window_type == "edit_user":
            self.modal_windows[title] = EditUserModalWindow(self.page, title)
        else:
            assert False, "Unsupported modal window type"

    def add_new_user(self, user_data: dict) -> bool:
        """Добавляет нового пользователя или обрабатывает ошибку при дубликате.

        Args:
            user_data: Данные пользователя (name, role, password).

        Returns:
            bool: True если пользователь успешно добавлен, False если пользователь уже существует.

        Raises:
            AssertionError: Если открылось alert окно отличное от success или error,
                        или если текст alert не соответствует ожидаемому.
        """

        add_user_window = self.get_modal_window("add_local_user")

        auth_type = user_data.get("auth_type")
        if auth_type == "active_directory":
            add_user_window.check_active_directory_checkbox()
            self.add_modal_window("add_AD_user", "")
            add_user_window = self.get_modal_window("add_AD_user")

        add_user_window.new_user(user_data)

        is_added = False
        alert_type = self.alert.get_alert_type()
        if alert_type == "success":
            self.alert.check_alert_presence(' Новый пользователь \n успешно добавлен! ')
            self.alert.check_alert_absence(' Новый пользователь \n успешно добавлен! ')
            is_added = True
        elif alert_type == "error":
            self.alert.check_alert_presence(f' Имя {user_data["name"]} уже \n используется ')
            self.alert.check_alert_absence(f' Имя {user_data["name"]} уже \n используется ')
        else:
            assert False, f"Got unexpected alert type {alert_type}"

        return is_added

    def close_add_AD_user_window(self) -> None:
        """Закрывает окно добавления пользователя."""

        self.close_modal_window("add_AD_user")

    def close_add_AD_user_window_by_toolbar_button(self) -> None:
        """Закрывает окно добавления пользователя через тулбар."""

        self.close_modal_window_by_toolbar_button("add_AD_user")

    def close_add_user_window(self) -> None:
        """Закрывает окно добавления пользователя."""

        self.close_modal_window("add_local_user")

    def close_add_user_window_by_toolbar_button(self) -> None:
        """Закрывает окно добавления пользователя через тулбар."""

        self.close_modal_window_by_toolbar_button("add_local_user")

    def close_edit_user_window(self, title: str) -> None:
        """Закрывает окно редактирования пользователя.

        Args:
            title: Имя пользователя (заголовок окна).
        """

        self.close_modal_window(title)

    def close_edit_user_window_by_toolbar_button(self, title: str) -> None:
        """Закрывает окно редактирования через кнопку в тулбаре.

        Args:
            title: Имя пользователя (заголовок окна).
        """

        self.close_modal_window_by_toolbar_button(title)

    def close_modal_window(self, title: str) -> None:
        """Закрывает модальное окно через кнопку закрытия.

        Args:
            title: Заголовок окна.
        """

        modal_window = self.get_modal_window(title)
        modal_window.close_window()
        self.delete_modal_window(title)

    def close_modal_window_by_toolbar_button(self, title: str) -> None:
        """Закрывает модальное окно через кнопку в тулбаре.

        Args:
            title: Заголовок окна.
        """

        modal_window = self.get_modal_window(title)
        modal_window.close_window_by_toolbar_button()
        self.delete_modal_window(title)

    def delete_modal_window(self, title: str) -> None:
        """Удаляет модальное окно из коллекции.

        Args:
            title: Заголовок окна.

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

        if self.modal_windows.get(title) is None:
            assert False, f"Modal window with title '{title}' not found"
        self.modal_windows[title] = None

    def delete_user(self, user_name: str) -> None:
        """Удаляет пользователя.

        Args:
            user_name: Имя пользователя.

        Raises:
            AssertionError: Если нет сообщения об успешном удалении.
        """

        self.get_modal_window(user_name).delete_user()

        alert_type = self.alert.get_alert_type()
        assert alert_type == "success", f"Expected success alert, but got {alert_type} alert"

        self.alert.check_alert_presence('\nПользователь удалён\n')
        self.alert.check_alert_absence('\nПользователь удалён\n')

    def edit_user(self, user_name: str, user_data: dict) -> None:
        """Редактирует данные пользователя.

        Args:
            user_name: Имя пользователя.
            user_data: Новые данные пользователя.

        Raises:
            AssertionError: Если нет сообщения об успешном обновлении.
        """

        self.get_modal_window(user_name).edit_user(user_data)

        alert_type = self.alert.get_alert_type()
        assert alert_type == "success", f"Expected success alert, but got {alert_type} alert"

        self.alert.check_alert_presence('\nОбновление успешно\n')
        self.alert.check_alert_absence('\nОбновление успешно\n')

    def find_user_in_table(self, name: str, role: str) -> int:
        """Ищет пользователя в таблице.

        Args:
            name: Имя пользователя.
            role: Роль пользователя.

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

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

        self.page.wait_for_timeout(1000)

        table_content = self.users_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, user_info in enumerate(table_content):
            if name in user_info and role in user_info:
                return row_index
        return -1

    def get_modal_window(self, title: str) -> ModalWindowComponent:
        """Возвращает модальное окно по заголовку.

        Args:
            title: Заголовок окна.

        Returns:
            ModalWindowComponent: Экземпляр модального окна.

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

        modal_window = self.modal_windows.get(title)
        if modal_window is None:
            assert False, f"Modal window with title '{title}' not found"
        return modal_window

    def open_add_user_window(self) -> None:
        """Открывает окно добавления пользователя.

        Raises:
            AssertionError: Если кнопки недоступны или окно не открылось.
        """

        if self.toolbar.is_button_not_present("close"):
            self.toolbar.check_button_visibility("edit")
            self.toolbar.click_button("edit")

        self.toolbar.check_button_visibility("add_user")
        self.toolbar.click_button("add_user")
        self.page.wait_for_timeout(700)

        self.add_modal_window("add_local_user", "")
        self.get_modal_window("add_local_user").check_by_window_title()

    def open_edit_user_page_by_index(self, row_index: int) -> tuple:
        """Открывает окно редактирования по индексу строки.

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

        Returns:
            tuple: (имя пользователя, роль).

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

        self.page.wait_for_timeout(2000)

        tmp_dict = {"admin": "Администратор", "manager": "Контактное лицо",
                   "operator": "Оператор"}
        table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA)

        if len(table_content) == 0:
            assert False, "The contents of the table are missing"

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

        if row_index >= len(table_content):
            assert False, "Row_index is out of range"

        user_name = table_content[row_index][0]
        for key, val in tmp_dict.items():
            if user_name == val:
                user_name = key

        role = table_content[row_index][2]

        self.page.locator(TableLocators.TABLE_WORK_AREA).locator(
            "//tbody/tr").nth(row_index).click()
        self.add_modal_window("edit_user", user_name)
        self.get_modal_window(user_name).check_by_window_title()

        return user_name, role

    def open_edit_user_page_by_user(self, user_name: str, role: str) -> None:
        """Открывает окно редактирования по имени и роли.

        Args:
            user_name: Имя пользователя.
            role: Роль пользователя.

        Raises:
            AssertionError: Если пользователь не найден.
        """

        row_index = self.find_user_in_table(user_name, role)
        if row_index == -1:
            assert False, f"User with name {user_name} and role {role} has not been found"

        self.page.locator(TableLocators.TABLE_WORK_AREA).locator("//tbody/tr").nth(row_index).click()
        self.add_modal_window("edit_user", user_name)
        self.get_modal_window(user_name).check_by_window_title()

    def reset_password(self, user_name: str) -> str:
        """Сбрасывает пароль пользователя.

        Args:
            user_name: Имя пользователя.

        Returns:
            str: Новый пароль (если получен).
        """

        new_password = ""
        self.get_modal_window(user_name).reset_password()

        self.alert.check_alert_presence("")
        alert_message = self.alert.get_text()
        if len(alert_message) > 0:
            new_password = re.findall(r'[\d]+', alert_message)[0]

        return new_password

    def transform_to_add_AD_user_window(self):
        """Трансформирует модальное окно добавления локального пользователя
           в окно добавления пользователя Active Directory с помощью нажатия
           чек-бокса Active Directory.
        """

        self.get_modal_window("add_local_user").check_active_directory_checkbox()
        modal_window = self.modal_windows.get("add_AD_user")
        if modal_window is None:
            self.add_modal_window("add_AD_user", "")

    def transform_to_add_user_window(self):
        """Трансформирует модальное окно добавления пользователя Active Directory
           в окно добавления локального пользователя с помощью снятия отметки с
           чек-бокса Active Directory.
        """

        self.get_modal_window("add_AD_user").uncheck_active_directory_checkbox()
        modal_window = self.modal_windows.get("add_local_user")
        if modal_window is None:
            self.add_modal_window("add_local_user", "")

    # Проверки:
    def check_add_AD_user_window_content(self) -> None:
        """Проверяет содержимое окна добавления пользователя через Active Directory."""

        self.get_modal_window("add_AD_user").check_content()

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

        self.get_modal_window("add_local_user").check_content()

    def check_edit_user_window_content(self, user_name: str, role: str) -> None:
        """Проверяет содержимое окна редактирования.

        Args:
            user_name: Имя пользователя.
            role: Роль пользователя.
        """

        edit_user_window = self.get_modal_window(user_name)
        edit_user_window.check_content(user_name, role)

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

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

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

        expected_headers = ['Имя пользователя', 'Тип авторизации', 'Роль',
                           'E-mail', 'Номер для СМС']
        table_content = self.users_table.read(TableLocators.TABLE_WORK_AREA)

        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_users_table_content(table_content)

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

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

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

    def should_be_toolbar_buttons(self) -> None:
        """Проверяет наличие и функциональность кнопок тулбара.

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

        self.toolbar.check_button_visibility("edit")
        self.toolbar.check_button_tooltip("edit", "Редактировать")

        self.toolbar.get_button_by_name("edit").click()
        self.toolbar.check_button_visibility("add_user")
        self.toolbar.check_button_visibility("close")
        self.toolbar.check_button_tooltip("add_user", "Добавить")
        self.toolbar.check_button_tooltip("close", "Закрыть")

        self.toolbar.get_button_by_name("close").click()
        self.toolbar.check_button_visibility("edit")

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

        Args:
            name: Имя пользователя.
            role: Роль пользователя.

        Raises:
            AssertionError: Если пользователь не найден.
        """

        found = self.find_user_in_table(name, role)
        if found == -1:
            assert False, f"User with name {name} and role {role} has not been found"

    def should_be_users_table(self) -> None:
        """Проверяет наличие таблицы пользователей.

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

        self.users_table.check_visibility(TableLocators.TABLE_WORK_AREA,"Users table is missing")

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

        Args:
            name: Имя пользователя.
            role: Роль пользователя.

        Raises:
            AssertionError: Если пользователь найден.
        """

        found = self.find_user_in_table(name, role)
        if found != -1:
            assert False, f"User with name {name} and role {role} has been found"

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

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

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

        expected_users_list = []

        query = {
            "id": ["/catalogs/user"],
            "data": {
                "namePath": True,
                "children": {"flatten": True}
            }
        }

        response = self.send_post_api_request("e-cmdb/api/query", query)
        response_body = self.get_response_body(response)

        for item in response_body[0]["children"]:
            user_info = []
            user_name = item["name"]

            # НЕ преобразуем имя пользователя - оставляем как есть из БД
            user_info.append(user_name)

            if item["type_auth"] is not None:
                user_info.append(item["type_auth"])
            else:
                user_info.append("")

            if item["role"] is not None:
                role = item["role"]
                # Убрали вызов .keys()
                if role in roles_dict:
                    item["role"] = roles_dict[role]
                user_info.append(item["role"])
            else:
                user_info.append("")

            if item["email"] is not None:
                user_info.append(item["email"])
            else:
                user_info.append("")

            if item["sms_phone"] is not None:
                user_info.append(item["sms_phone"])
            else:
                user_info.append("")

            expected_users_list.append(user_info)

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

        self.check_lists_equals(
            users_table,
            expected_users_list,
            "Actual users list is not equal expected users list on base db"
        )
