"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RowActionsHelper = void 0;
const test_1 = require("@playwright/test");
const logger_1 = require("../../../../utils/logger");
const timeouts_1 = require("../../../../timeouts");
const test_errors_1 = require("../../../../utils/test-errors");
class RowActionsHelper {
    constructor(page, formHelper, tryFindErrorMessageFn, confirmActionFn, modalWindowBody) {
        this.page = page;
        this.formHelper = formHelper;
        this.checkNoHaveErrorMessageFn = tryFindErrorMessageFn;
        this.confirmActionFn = confirmActionFn;
        this.modalWindowBody = modalWindowBody;
    }
    /**
     * Получает локатор действия - использует готовый локатор
     * @param actionLocator - готовый локатор действия
     * @returns локатор действия
     */
    getRowActionLocator(actionLocator) {
        return actionLocator;
    }
    /**
    * Открывает меню действий над строкой
    * @param menuButtonLocator - готовый локатор кнопки меню
    */
    async openRowActionsMenuBase(menuButtonLocator) {
        await menuButtonLocator.click();
    }
    /**
     * Закрывает меню действий над строкой
     */
    async closeRowActionsMenuBase() {
        await this.page.keyboard.press('Escape');
    }
    /**
    * Выполняет действие со строкой
    * @param actionKey - ключ действия (например, 'MenuItemEdit' или 'ButtonEdit')
    * @param rowActionsConfig - конфигурация действий строки
    * @param rowActionButtons - Record с локаторами кнопок действий (готовые локаторы)
    * @param rowActionMenuItems - Record с локаторами пунктов меню (всегда на странице)
    */
    async clickRowActionBase(actionKey, rowActionsConfig, rowActionButtons = null, rowActionMenuItems = null) {
        logger_1.logger.debug(`Выполнение действия ${actionKey}`, `${this.constructor.name}.clickRowAction`);
        if (rowActionsConfig.actions.type === 'menu') {
            // Открываем меню
            const menuButtonKey = rowActionsConfig.actions.menuButtonKey;
            if (!rowActionButtons || !rowActionButtons[menuButtonKey]) {
                logger_1.logger.error(`Локатор кнопки меню "${menuButtonKey}" не найден. ActionKey: ${actionKey}`, `${this.constructor.name}.clickRowActionBase`);
                throw new Error(`Локатор кнопки меню "${menuButtonKey}" не найден. ActionKey: ${actionKey}`);
            }
            await this.openRowActionsMenuBase(rowActionButtons[menuButtonKey]);
            // Получаем локатор пункта меню
            if (!rowActionMenuItems) {
                logger_1.logger.error(`rowActionMenuItems не определены. ActionKey: ${actionKey}`, `${this.constructor.name}.clickRowActionBase`);
                throw new Error(`rowActionMenuItems не определены. ActionKey: ${actionKey}`);
            }
            const menuItem = rowActionMenuItems[actionKey];
            if (!menuItem) {
                logger_1.logger.error(`Локатор пункта меню "${actionKey}" не найден в rowActionMenuItems`, `${this.constructor.name}.clickRowActionBase`);
                throw new Error(`Локатор пункта меню "${actionKey}" не найден в rowActionMenuItems`);
            }
            // Ждем стабильности меню с retry-логикой
            await test_1.expect.poll(async () => {
                const isVisible = await menuItem.isVisible();
                if (!isVisible) {
                    return false;
                }
                // Проверяем, что элемент прикреплен к DOM и стабилен
                try {
                    await menuItem.waitFor({ state: 'attached', timeout: timeouts_1.TIMEOUTS.ELEMENT_STABLE_WAIT });
                    return true;
                }
                catch {
                    return false;
                }
            }, {
                message: `Пункт меню "${actionKey}" не стал стабильным`,
                timeout: timeouts_1.TIMEOUTS.ACTION
            }).toBeTruthy();
            // Кликаем с явным таймаутом
            await menuItem.click({ timeout: timeouts_1.TIMEOUTS.ACTION, force: false });
            await this.checkNoHaveErrorMessageFn();
        }
        else {
            // Кликаем по отдельной кнопке
            if (!rowActionButtons || !rowActionButtons[actionKey]) {
                logger_1.logger.error(`Локатор кнопки "${actionKey}" не найден`, `${this.constructor.name}.clickRowActionBase`);
                throw new Error(`Локатор кнопки "${actionKey}" не найден`);
            }
            await test_1.test.step(`Выполнение действия ${actionKey}`, async () => {
                const button = this.getRowActionLocator(rowActionButtons[actionKey]);
                await button.click();
                await this.checkNoHaveErrorMessageFn();
                await this.page.waitForLoadState('networkidle');
            });
        }
    }
    /**
    * Проверяет видимость кнопок действий строки
    * @param rowActionsConfig - конфигурация действий строки
    * @param rowActionButtons - Record с локаторами кнопок действий (готовые локаторы)
    * @param rowActionMenuItems - Record с локаторами пунктов меню (всегда на странице)
    */
    async checkRowActionsBase(rowActionsConfig, rowActionButtons = null, rowActionMenuItems = null) {
        logger_1.logger.debug(`Проверка действий строки`, `${this.constructor.name}.checkRowActions`);
        if (rowActionsConfig.actions.type === 'menu') {
            // Открываем меню
            const menuButtonKey = rowActionsConfig.actions.menuButtonKey;
            if (!rowActionButtons || !rowActionButtons[menuButtonKey]) {
                logger_1.logger.error(`Локатор кнопки меню "${menuButtonKey}" не найден`, `${this.constructor.name}.checkRowActions`);
                throw new Error(`Локатор кнопки меню "${menuButtonKey}" не найден`);
            }
            await this.openRowActionsMenuBase(rowActionButtons[menuButtonKey]);
            // Проверяем пункты меню
            if (!rowActionMenuItems) {
                logger_1.logger.error('rowActionMenuItems не определены', `${this.constructor.name}.checkRowActions`);
                throw new Error('rowActionMenuItems не определены');
            }
            for (const menuItemKey of rowActionsConfig.actions.menuItems) {
                const menuItem = rowActionMenuItems[menuItemKey];
                if (!menuItem) {
                    logger_1.logger.warn(`Локатор пункта меню ${menuItemKey} не найден`, `${this.constructor.name}.checkRowActions`);
                    continue;
                }
                await test_1.test.step(`Проверка пункта меню ${menuItemKey}`, async () => {
                    await test_1.expect.soft(menuItem.first()).toBeVisible();
                });
            }
            // Проверяем скрытые действия
            if (rowActionsConfig.notVisibleActions && rowActionMenuItems) {
                for (const actionKey of rowActionsConfig.notVisibleActions) {
                    const menuItem = rowActionMenuItems[actionKey];
                    if (menuItem) {
                        await test_1.expect.soft(menuItem.first()).toBeHidden();
                    }
                }
            }
            await this.closeRowActionsMenuBase();
        }
        else {
            // Проверяем отдельные кнопки
            if (!rowActionButtons) {
                logger_1.logger.error('rowActionButtons должны быть определены', `${this.constructor.name}.checkRowActions`);
                throw new Error('rowActionButtons должны быть определены');
            }
            for (const buttonKey of rowActionsConfig.actions.buttons) {
                if (!rowActionButtons[buttonKey]) {
                    logger_1.logger.warn(`Локатор кнопки ${buttonKey} не найден`, `${this.constructor.name}.checkRowActions`);
                    continue;
                }
                await test_1.test.step(`Проверка кнопки ${buttonKey}`, async () => {
                    await test_1.expect.soft(rowActionButtons[buttonKey]).toBeVisible();
                });
            }
            // Проверяем скрытые кнопки
            if (rowActionsConfig.notVisibleActions) {
                for (const actionKey of rowActionsConfig.notVisibleActions) {
                    if (rowActionButtons[actionKey]) {
                        await test_1.expect.soft(rowActionButtons[actionKey]).toBeHidden();
                    }
                }
            }
        }
        logger_1.logger.info(`Проверка действий строки завершена`, `${this.constructor.name}.checkRowActions`);
    }
    /**
    * Открывает строку на редактирование (базовый метод)
    * @param rowActionsConfig - конфигурация действий строки
    * @param rowActionButtons - Record с локаторами кнопок действий (готовые локаторы)
    * @param rowActionMenuItems - Record с локаторами пунктов меню (всегда на странице)
    * @param modalWindowBody - локатор тела модального окна для проверки открытия (опционально)
    * @returns true если модальное окно успешно открыто
    */
    async editRowBase(rowActionsConfig, rowActionButtons = null, rowActionMenuItems = null, modalWindowBody) {
        logger_1.logger.info('Начало редактирования строки', `${this.constructor.name}.editRowBase`);
        // Определяем ключ действия для редактирования
        let editActionKey;
        if (rowActionsConfig.actions.type === 'menu') {
            editActionKey = rowActionsConfig.actions.menuItems.find(key => key.toLowerCase().includes('edit') || key.toLowerCase().includes('редактир'));
        }
        else {
            editActionKey = rowActionsConfig.actions.buttons.find(key => key.toLowerCase().includes('edit') || key.toLowerCase().includes('редактир'));
        }
        if (!editActionKey) {
            logger_1.logger.error('Действие редактирования не найдено в конфигурации', `${this.constructor.name}.editRowBase`);
            throw test_errors_1.ErrorFactory.data('editRow', 'Действие редактирования не найдено в конфигурации', undefined, 'editActionKey', undefined, { actionsType: rowActionsConfig.actions.type });
        }
        await this.clickRowActionBase(editActionKey, rowActionsConfig, rowActionButtons, rowActionMenuItems);
        // Проверяем открытие модального окна
        if (modalWindowBody) {
            await (0, test_1.expect)(modalWindowBody).toBeVisible();
            logger_1.logger.debug('Модальное окно редактирования успешно открыто', `${this.constructor.name}.editRowBase`);
            return true;
        }
        logger_1.logger.debug('Модальное окно редактирования не было указано', `${this.constructor.name}.editRowBase`);
        return false;
    }
    /**
    * Открывает строку на просмотр (readonly) (базовый метод)
    * @param rowActionsConfig - конфигурация действий строки
    * @param rowActionButtons - Record с локаторами кнопок действий (готовые локаторы)
    * @param rowActionMenuItems - Record с локаторами пунктов меню (всегда на странице)
    * @param modalWindowBody - локатор тела модального окна для проверки открытия (опционально)
    * @returns true если модальное окно успешно открыто
    */
    async viewRowBase(rowActionsConfig, rowActionButtons = null, rowActionMenuItems = null, modalWindowBody) {
        logger_1.logger.info('Начало просмотра строки', `${this.constructor.name}.viewRowBase`);
        // Определяем ключ действия для просмотра
        let viewActionKey;
        if (rowActionsConfig.actions.type === 'menu') {
            viewActionKey = rowActionsConfig.actions.menuItems.find(key => key.toLowerCase().includes('view') || key.toLowerCase().includes('просмотр'));
        }
        else {
            viewActionKey = rowActionsConfig.actions.buttons.find(key => key.toLowerCase().includes('view') || key.toLowerCase().includes('просмотр'));
        }
        if (!viewActionKey) {
            logger_1.logger.error('Действие просмотра не найдено в конфигурации', `${this.constructor.name}.viewRowBase`);
            throw test_errors_1.ErrorFactory.data('viewRow', 'Действие просмотра не найдено в конфигурации', undefined, 'viewActionKey', undefined, { actionsType: rowActionsConfig.actions.type });
        }
        await this.clickRowActionBase(viewActionKey, rowActionsConfig, rowActionButtons, rowActionMenuItems);
        // Проверяем открытие модального окна
        if (modalWindowBody) {
            await (0, test_1.expect)(modalWindowBody).toBeVisible();
            logger_1.logger.debug('Модальное окно просмотра успешно открыто', `${this.constructor.name}.viewRowBase`);
            return true;
        }
        logger_1.logger.debug('Модальное окно просмотра не было указано', `${this.constructor.name}.viewRowBase`);
        return false;
    }
    /**
    * Удаляет строку (с подтверждением, если требуется) (базовый метод)
    * @param rowActionsConfig - конфигурация действий строки
    * @param rowActionButtons - Record с локаторами кнопок действий (готовые локаторы)
    * @param rowActionMenuItems - Record с локаторами пунктов меню (всегда на странице)
    * @param confirmDelete - нужно ли подтверждение удаления (по умолчанию true)
    * @returns true если удаление успешно
    */
    async deleteRowBase(rowActionsConfig, rowActionButtons = null, rowActionMenuItems = null, confirmDelete = true) {
        logger_1.logger.info(`Начало удаления строки (подтверждение: ${confirmDelete})`, `${this.constructor.name}.deleteRowBase`);
        // Определяем ключ действия для удаления
        let deleteActionKey;
        if (rowActionsConfig.actions.type === 'menu') {
            deleteActionKey = rowActionsConfig.actions.menuItems.find(key => key.toLowerCase().includes('delete') || key.toLowerCase().includes('удал'));
        }
        else {
            deleteActionKey = rowActionsConfig.actions.buttons.find(key => key.toLowerCase().includes('delete') || key.toLowerCase().includes('удал'));
        }
        if (!deleteActionKey) {
            logger_1.logger.error('Действие удаления не найдено в конфигурации', `${this.constructor.name}.deleteRowBase`);
            throw test_errors_1.ErrorFactory.data('deleteRow', 'Действие удаления не найдено в конфигурации', undefined, 'deleteActionKey', undefined, { actionsType: rowActionsConfig.actions.type });
        }
        await this.clickRowActionBase(deleteActionKey, rowActionsConfig, rowActionButtons, rowActionMenuItems);
        if (confirmDelete) {
            await this.confirmActionFn();
        }
        logger_1.logger.debug('Строка успешно удалена', `${this.constructor.name}.deleteRowBase`);
        return true;
    }
    /**
    * Редактирует строку с заполнением формы, сохранением и проверкой результата
    * Универсальный базовый метод для BaseGridPage и BaseCard
    * @param editRowFn - функция для открытия редактирования (возвращает true если модальное окно открыто)
    * @param formFields - Объект с полями для заполнения
    * @param getModalFormLocatorsFn - функция для получения всех локаторов полей формы модального окна
    * @param getModalButtonsFn - функция для получения кнопок модального окна
    * @param saveButtonKey - ключ кнопки сохранения (по умолчанию 'ButtonSave')
    * @param verifyRowFn - опциональная функция для проверки результата после сохранения
    * @param performModalTerminalActionToCloseModalWindowFn - колбэк для выполнения терминального действия (сохранение): клик → ожидание скрытия модалки → проверка ошибок
    */
    async editRowAndVerifyBase(editRowFn, formFields, getModalFormLocatorsFn, getModalButtonsFn, saveButtonKey = 'ButtonSave', performModalTerminalActionToCloseModalWindowFn, verifyRowFn) {
        logger_1.logger.info('Начало редактирования строки с сохранением и проверкой', `${this.constructor.name}.editRowAndVerifyBase`);
        // Открываем редактирование
        const modalOpened = await editRowFn();
        if (!modalOpened) {
            logger_1.logger.error('Модальное окно редактирования не открылось', `${this.constructor.name}.editRowAndVerifyBase`);
            throw new Error(`Модальное окно редактирования не открылось. SaveButtonKey: ${saveButtonKey}`);
        }
        // Заполняем форму
        const formLocators = getModalFormLocatorsFn();
        const hasFormLocators = formLocators && (formLocators.textFieldsLocators || formLocators.comboboxFieldsLocators || formLocators.fileFieldsLocators ||
            formLocators.radioButtonsLocators || formLocators.daDataFieldsLocators || formLocators.checkboxesLocators || formLocators.toggleButtonsLocators);
        if (hasFormLocators) {
            logger_1.logger.debug(`Заполнение формы редактирования`, `${this.constructor.name}.editRowAndVerifyBase`);
            await this.formHelper.fillFormFields({
                textFieldsData: formFields.textFieldsData,
                comboboxFieldsData: formFields.comboboxFieldsData,
                fileFieldsData: formFields.fileFieldsData,
                radioButtonsData: formFields.radioButtonsData,
                daDataFieldsData: formFields.daDataFieldsData,
                checkboxesData: formFields.checkboxesData,
                toggleButtonsData: formFields.toggleButtonsData
            }, formLocators, 'формы редактирования');
        }
        // Сохраняем
        const modalButtons = getModalButtonsFn();
        if (modalButtons && modalButtons[saveButtonKey]) {
            await performModalTerminalActionToCloseModalWindowFn(modalButtons[saveButtonKey], this.modalWindowBody, `Сохранение изменений ${saveButtonKey}`);
        }
        // Проверяем результат (если указана функция проверки)
        if (verifyRowFn) {
            logger_1.logger.debug('Проверка результата редактирования', `${this.constructor.name}.editRowAndVerifyBase`);
            await verifyRowFn();
        }
    }
    /**
    * Просматривает строку и проверяет данные в модальном окне
    * Универсальный базовый метод для BaseGridPage и BaseCard
    * @param viewRowFn - функция для открытия просмотра (возвращает true если модальное окно открыто)
    * @param expectedData - ожидаемые данные для проверки
    * @param getModalInputsFn - функция для получения полей модального окна
    * @param getModalButtonsFn - функция для получения кнопок модального окна
    * @param performModalTerminalActionToCloseModalWindowFn - колбэк для закрытия модального окна: клик → ожидание скрытия → проверка ошибок
    */
    async viewRowAndVerifyBase(viewRowFn, expectedData, getModalInputsFn, getModalButtonsFn, performModalTerminalActionToCloseModalWindowFn) {
        logger_1.logger.info(`Начало просмотра строки с проверкой данных (${Object.keys(expectedData).length} полей)`, `${this.constructor.name}.viewRowAndVerifyBase`);
        await test_1.test.step('Просмотр строки с проверкой данных', async () => {
            // Открываем просмотр
            const modalOpened = await viewRowFn();
            if (!modalOpened) {
                logger_1.logger.error(`Модальное окно просмотра не открылось. Ожидаемые поля: ${Object.keys(expectedData).join(', ')}`, `${this.constructor.name}.viewRowAndVerifyBase`);
                throw new Error(`Модальное окно просмотра не открылось. Ожидаемые поля: ${Object.keys(expectedData).join(', ')}`);
            }
            // Проверяем данные в модальном окне
            const modalInputs = getModalInputsFn();
            if (modalInputs) {
                logger_1.logger.debug(`Проверка данных в модальном окне (${Object.keys(expectedData).length} полей)`, `${this.constructor.name}.viewRowAndVerifyBase`);
                await test_1.test.step('Проверка данных в модальном окне', async () => {
                    for (const [inputKey, expectedValue] of Object.entries(expectedData)) {
                        const input = modalInputs[inputKey];
                        if (input) {
                            await test_1.test.step(`Проверка поля ${inputKey}`, async () => {
                                const actualValue = await input.inputValue();
                                test_1.expect.soft(actualValue).toBe(expectedValue);
                            });
                        }
                    }
                });
            }
            // Закрываем модальное окно
            const modalButtons = getModalButtonsFn();
            if (modalButtons) {
                const closeButton = modalButtons['ButtonExit'] || modalButtons['ButtonClose'];
                if (closeButton) {
                    await performModalTerminalActionToCloseModalWindowFn(closeButton, this.modalWindowBody, 'Закрытие модального окна просмотра');
                }
            }
        });
    }
    /**
    * Удаляет строку и проверяет, что она исчезла
    * Универсальный базовый метод для BaseGridPage и BaseCard
    * @param findRowFn - функция для поиска строки (возвращает Locator строки или null)
    * @param deleteRowFn - функция для удаления строки
    * @param findRowSilentFn - функция для поиска строки без ошибок (возвращает Locator строки или null)
    * @param rowData - данные строки для проверки отсутствия
    */
    async deleteRowAndVerifyBase(findRowFn, deleteRowFn, findRowSilentFn, rowData) {
        logger_1.logger.info(`Начало удаления строки с проверкой отсутствия: ${JSON.stringify(rowData)}`, `${this.constructor.name}.deleteRowAndVerifyBase`);
        await test_1.test.step('Удаление строки и проверка ее отсутствия', async () => {
            await test_1.test.step('Удаление строки', async () => {
                const row = await findRowFn();
                if (!row) {
                    logger_1.logger.error('Строка для удаления не найдена', `${this.constructor.name}.deleteRowAndVerifyBase`);
                    throw test_errors_1.ErrorFactory.data('deleteRow', 'Строка для удаления не найдена', undefined, 'rowData', rowData, { rowData: JSON.stringify(rowData) });
                }
                logger_1.logger.debug('Выполнение удаления строки', `${this.constructor.name}.deleteRowAndVerifyBase`);
                await deleteRowFn(row);
            });
            // Проверяем, что строка исчезла
            await test_1.test.step('Проверка отсутствия строки после удаления', async () => {
                logger_1.logger.debug('Проверка отсутствия строки после удаления', `${this.constructor.name}.deleteRowAndVerifyBase`);
                // Используем expect.poll для ожидания исчезновения строки из таблицы
                await test_1.expect.poll(async () => {
                    const rowAfterDelete = await findRowSilentFn();
                    // Возвращаем true, если строка не найдена (null), false если найдена
                    return rowAfterDelete === null;
                }, {
                    message: `Строка не была удалена из таблицы → ${JSON.stringify(rowData)}`,
                    timeout: timeouts_1.TIMEOUTS.TABLE_UPDATE
                }).toBeTruthy();
                logger_1.logger.debug('Строка успешно удалена и отсутствует в таблице', `${this.constructor.name}.deleteRowAndVerifyBase`);
            });
        });
    }
    /**
     * Реализация метода toggleActivation
     */
    async toggleActivation(rowLocatorOrBlockKey, actionOrRowLocator, actionTypeOrAction, actionTypeOrRequireConfirmation, requireConfirmation) {
        if (typeof rowLocatorOrBlockKey === 'string') {
            // Карточка: (blockKey, rowLocator, action, actionType?, requireConfirmation?)
            const blockKey = rowLocatorOrBlockKey;
            const rowLocator = actionOrRowLocator;
            const action = actionTypeOrAction;
            const finalActionType = typeof actionTypeOrRequireConfirmation === 'string'
                ? actionTypeOrRequireConfirmation
                : undefined;
            const finalRequireConfirmation = typeof actionTypeOrRequireConfirmation === 'boolean'
                ? actionTypeOrRequireConfirmation
                : requireConfirmation || false;
            await this.toggleActivationForCard(blockKey, rowLocator, action, finalActionType, finalRequireConfirmation);
        }
        else {
            // Грид: (rowLocator, action, actionType?, requireConfirmation?)
            const rowLocator = rowLocatorOrBlockKey;
            const action = actionOrRowLocator;
            const finalActionType = typeof actionTypeOrAction === 'string' && (actionTypeOrAction === 'menu' || actionTypeOrAction === 'button')
                ? actionTypeOrAction
                : undefined;
            const finalRequireConfirmation = typeof actionTypeOrRequireConfirmation === 'boolean'
                ? actionTypeOrRequireConfirmation
                : requireConfirmation || false;
            await this.toggleActivationForGrid(rowLocator, action, finalActionType, finalRequireConfirmation);
        }
    }
    /**
     * Вспомогательный метод для активации/деактивации в гриде.
     * Должен быть переопределен в BaseGridPage
     */
    async toggleActivationForGrid(_rowLocator, _action, _actionType, _requireConfirmation) {
        throw new Error('toggleActivationForGrid должен быть переопределен в BaseGridPage');
    }
    /**
     * Вспомогательный метод для активации/деактивации в карточке.
     * Должен быть переопределен в BaseCard
     */
    async toggleActivationForCard(_blockKey, _rowLocator, _action, _actionType, _requireConfirmation) {
        throw new Error('toggleActivationForCard должен быть переопределен в BaseCard');
    }
}
exports.RowActionsHelper = RowActionsHelper;
