"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseCard = void 0;
const test_1 = require("@playwright/test");
const BasePage_1 = require("../BasePage/BasePage");
const logger_1 = require("../../utils/logger");
const timeouts_1 = require("../../timeouts");
const services_1 = require("./services");
const FormDataFilterUtils_1 = require("../shared/form/FormDataFilterUtils");
const TableRowService_1 = require("../shared/table/TableRowService");
const table_scope_1 = require("../shared/table/table-scope");
const ConfigResolver_1 = require("../shared/config/ConfigResolver");
const visibility_1 = require("../shared/visibility");
class BaseCard extends BasePage_1.BasePage {
    constructor(page) {
        super(page);
        this.page = page;
        this.tableRowService = new TableRowService_1.TableRowService(this.page, this.textUtils);
        this.cardBlockFormService = this.createCardBlockFormService();
        this.cardBlockRowActionsService = this.createCardBlockRowActionsService();
    }
    /**
     * Создаёт сервис действий над строками в блоках карточки.
     * Зависимости (конфиг, локаторы, низкоуровневые методы BasePage) передаются через deps.
     */
    createCardBlockRowActionsService() {
        return new services_1.CardBlockRowActionsService({
            getRole: () => this.getRoleOrThrow(),
            validateBlockParams: (blockKey, role) => this.validateBlockParams(blockKey, role),
            getConfig: (blockKey, role) => this.getBlockRowActionsConfiguration(blockKey, role),
            getRowActionButtons: (blockKey, rowLocator) => this.getBlockRowActionButtons(blockKey, rowLocator),
            getMenuItems: (blockKey) => this.getBlockRowActionMenuItems(blockKey),
            orchestrator: this.rowActionsOrchestrator,
            findModalWindowConfig: (blockKey, modalWindowKey) => this.findBlockModalWindowConfig(blockKey, modalWindowKey),
            confirmAction: () => this.confirmAction()
        });
    }
    createCardBlockFormService() {
        return new services_1.CardBlockFormService({
            getRole: () => this.getRoleOrThrow(),
            validateBlockParams: (blockKey, role) => this.validateBlockParams(blockKey, role),
            getBlockTableLabel: (blockKey) => this.getBlockTableLabel(blockKey),
            findBlockInlineFormConfig: (blockKey, inlineFormKey) => this.findBlockInlineFormConfig(blockKey, inlineFormKey),
            getBlockButtons: (blockKey) => this.getBlockButtons(blockKey),
            findBlockModalWindowConfig: (blockKey, modalKey) => this.findBlockModalWindowConfig(blockKey, modalKey),
            getBlockModalWindowFormLocators: (blockKey, modalKey) => this.getBlockModalWindowFormLocators(blockKey, modalKey),
            getBlockModalWindowButtons: (blockKey, modalKey) => this.getBlockModalWindowButtons(blockKey, modalKey),
            performModalTerminalActionToCloseModalWindow: (button, stepName) => this.performModalTerminalActionToCloseModalWindow(button, stepName),
            verifyTableRowInBlock: (rowKey, rowData, tableLabel, isNewlyAdded, onRowFound) => this.verifyTableRowInBlock(rowKey, rowData, tableLabel, isNewlyAdded, onRowFound),
            openBlockModalWindow: (blockKey, modalWindowKey) => this.openBlockModalWindow(blockKey, modalWindowKey),
            formHelperFillFormFields: (data, locators, context) => this.formHelper.fillFormFields(data, locators, context),
            formHelperVerifyFormFieldsValues: (values, locators, context) => this.formHelper.verifyFormFieldsValues(values, locators, context),
            getBlockFormWithFieldsLocators: (blockKey, inlineFormKey) => this.getBlockFormWithFieldsLocators(blockKey, inlineFormKey),
            executeWithErrorCheck: (actionDescription, action) => this.uiNotifications.executeWithErrorCheck(actionDescription, action),
        });
    }
    /**
     * Возвращает aria-label таблицы блока по blockKey (для getByLabel).
     * @param blockKey - ключ блока
     */
    getBlockTableLabel(blockKey) {
        const label = this.resolveBlockTableLabel(blockKey);
        if (!label?.trim()) {
            throw new Error(`Метка таблицы для блока ${blockKey} не найдена`);
        }
        return label;
    }
    /**
     * Возвращает aria-label таблицы блока по blockKey.
     * Переопределить в наследнике карточки (делегировать в *Page.config.ts).
     * @param blockKey - ключ блока
     */
    resolveBlockTableLabel(_blockKey) {
        return undefined;
    }
    /**
     * Валидирует входные параметры для методов работы с блоками
     * @param blockKey - ключ блока
     * @param role - роль пользователя
     * @throws Error если параметры невалидны
     */
    validateBlockParams(blockKey, role) {
        if (!blockKey || typeof blockKey !== 'string' || blockKey.trim() === '') {
            throw new Error(`blockKey должен быть непустой строкой. Получено: ${blockKey}`);
        }
        const validRoles = ['Admin', 'Client', 'Agent', 'Bank'];
        if (!validRoles.includes(role)) {
            throw new Error(`role должен быть одним из: ${validRoles.join(', ')}. Получено: ${role}`);
        }
    }
    /**
     * Валидирует параметр tableLabel
     * @param tableLabel - метка таблицы
     * @throws Error если параметр невалиден
     */
    validateTableLabel(tableLabel) {
        if (!tableLabel || typeof tableLabel !== 'string' || tableLabel.trim() === '') {
            throw new Error(`tableLabel должен быть непустой строкой. Получено: ${tableLabel}`);
        }
    }
    // Общие методы для всех карточек
    //---------------------------------------------
    // Геттеры для получения конфигураций
    /**
     * Метод для получения конфигурации элементов блока карточки в зависимости от роли и контекста
     * !Для такого блока характерно наличие фильтров и таблицы в теле
     * Должен быть реализован в наследниках с учетом специфики каждого блока
     * @param blockKey - ключ блока (например, 'PersonalData', 'OrganizationData')
     * @param role - роль пользователя
     * @param context - контекст (Multi/Single) - опционально, используется для блоков, зависящих от количества организаций
     */
    getBlockConfiguration(_blockKey, _role, _context) {
        return null;
    }
    ;
    /**
     * Метод для получения конфигураций инлайн-форм блока в зависимости от роли.
     * По умолчанию возвращает пустой массив.
     * @param blockKey - ключ блока (например, 'PersonalData', 'OrganizationData')
     * @param role - роль пользователя
     */
    getBlockWithFormConfigurations(_blockKey, _role) {
        return [];
    }
    /**
     * Находит конфигурацию инлайн-формы блока по ключу.
     * @param blockKey - ключ блока
     * @param inlineFormKey - ключ инлайн-формы (из конфигурации блока)
     */
    findBlockInlineFormConfig(blockKey, inlineFormKey) {
        const role = this.getRoleOrThrow();
        return (0, ConfigResolver_1.resolveInlineFormConfig)(this.getBlockWithFormConfigurations(blockKey, role), inlineFormKey);
    }
    /**
    * Метод для получения конфигурации элементов блока в зависимости от роли и контекста
    * Должен быть реализован в наследниках с учетом специфики каждого блока
    * @param blockKey - ключ блока (например, 'PersonalData', 'OrganizationData')
    * @param role - роль пользователя
    */
    getNavigationBlockConfiguration(_blockKey, _role) {
        return null;
    }
    /**
    * Метод для получения конфигурации модальных окон блока в зависимости от роли
    * По умолчанию возвращает пустой массив
    * @param blockKey - ключ блока
    * @param role - роль пользователя
    * @returns Массив конфигураций модальных окон (может быть пустым, если модальных окон нет)
    */
    getBlockModalWindowConfigurations(_blockKey, _role) {
        return [];
    }
    /**
    * Метод для получения конфигурации действий строки блока в зависимости от роли
    * Должен быть переопределен в наследниках, если блок имеет действия строки
    * По умолчанию возвращает null (действия строки отсутствуют)
    * @param blockKey - ключ блока
    * @param role - роль пользователя
    * @returns Конфигурация действий строки или null, если действия не настроены
    */
    getBlockRowActionsConfiguration(_blockKey, _role) {
        return null;
    }
    /**
     * Возвращает Record testId → ключ для кнопок действий строки блока.
     * Переопределите в наследнике и верните объект для нужного blockKey, чтобы использовать стандартную реализацию getBlockRowActionButtons.
     * По умолчанию возвращает null.
     * @param blockKey - ключ блока
     */
    getBlockRowActionTestIds(_blockKey) {
        return null;
    }
    /**
     * Получает Record локаторов кнопок действий строки блока для конкретной строки.
     * Стандартная реализация строит локаторы по getBlockRowActionTestIds(blockKey) (getByTestId). Можно переопределить в наследниках при другой разметке.
     * @param blockKey - ключ блока
     * @param rowLocator - локатор строки, для которой нужно получить кнопки
     * @returns Record с локаторами кнопок действий строки или null
     */
    getBlockRowActionButtons(blockKey, rowLocator) {
        const testIds = this.getBlockRowActionTestIds(blockKey);
        if (!testIds || Object.keys(testIds).length === 0) {
            return null;
        }
        const rowActionButtons = {};
        for (const [key, testId] of Object.entries(testIds)) {
            if (testId) {
                rowActionButtons[key] = rowLocator.getByTestId(testId).first();
            }
        }
        return Object.keys(rowActionButtons).length > 0 ? rowActionButtons : null;
    }
    /**
     * Метод для получения Record локаторов пунктов меню действий строки блока
     * Должен быть переопределен в наследниках, если блок использует меню действий
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @returns Record с локаторами пунктов меню или null
     */
    getBlockRowActionMenuItems(_blockKey) {
        return null;
    }
    //----------------------------------------------------------------------------------------------------------
    //---------------------------------------------
    // Геттеры элементов блока
    /**
     * Метод для получения Record кнопок блока
     * @param blockKey - ключ блока
     */
    getBlockButtons(_blockKey) {
        return null;
    }
    ;
    /**
     * Возвращает Record элементов навигации блока.
     * Переопределите в наследнике карточки с блоком навигации.
     * @param blockKey - ключ блока навигации
     */
    getNavigationElements(_blockKey) {
        return null;
    }
    // Геттеры фильтров блока
    /**
     * Метод для получения Record фильтров блока
     * @param blockKey - ключ блока
     */
    getBlockTextFilters(_blockKey) {
        return null;
    }
    ;
    /**
     * Метод для получения Record combobox фильтров блока
     * @param blockKey - ключ блока
     */
    getBlockComboboxFilters(_blockKey) {
        return null;
    }
    ;
    /**
     * Метод для получения Record DaData фильтров блока
     * @param blockKey - ключ блока
     */
    getBlockDaDataFilters(_blockKey) {
        return null;
    }
    ;
    // Геттеры полей ввода блоков
    /**
     * Метод для получения Record полей ввода блока
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockTextFields(_blockKey, _inlineFormKey) {
        return null;
    }
    /**
     * Метод для получения Record combobox полей блока
     * Должен быть переопределен в наследниках, если блок имеет combobox поля
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockComboboxFields(_blockKey, _inlineFormKey) {
        return null;
    }
    /**
     * Метод для получения Record multiCombobox полей блока
     * Должен быть переопределен в наследниках, если блок имеет multiCombobox поля
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockMultiComboboxFields(_blockKey, _inlineFormKey) {
        return null;
    }
    /**
    * Метод для получения Record полей multiCombobox модального окна
    * Должен быть переопределен в наследниках, если модальное окно имеет поля multiCombobox
    * По умолчанию возвращает null
    * @param blockKey - ключ блока
    * @param _modalWindowKey - ключ модального окна
    */
    getBlockModalWindowMultiComboboxFields(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record полей для загрузки файлов блока
     * Должен быть переопределен в наследниках, если блок имеет поля для загрузки файлов
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockFileFields(_blockKey, _inlineFormKey) {
        return null;
    }
    /**
     * Метод для получения Record чекбоксов блока
     * Должен быть переопределен в наследниках, если блок имеет чекбоксы
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockCheckboxes(_blockKey, _inlineFormKey) {
        return null;
    }
    /**
     * Метод для получения Record toggle кнопок блока (switch)
     * Должен быть переопределен в наследниках, если блок имеет toggle кнопки
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockToggleButtons(_blockKey, _inlineFormKey) {
        return null;
    }
    /**
     * Метод для получения Record DaData полей блока
     * Должен быть переопределен в наследниках, если блок имеет DaData поля
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockDaDataFields(_blockKey, _inlineFormKey) {
        return null;
    }
    /**
     * Метод для получения Record radio кнопок блока
     * Должен быть переопределен в наследниках, если блок имеет radio кнопки
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param _inlineFormKey - ключ инлайн-формы
     */
    getBlockRadioButtons(_blockKey, _inlineFormKey) {
        return null;
    }
    //---------------------------------------------
    /**
     * Находит конфигурацию модального окна блока по ключу.
     * @param blockKey - ключ блока
     * @param modalWindowKey - опциональный ключ модального окна
     * @returns найденная конфигурация
     */
    findBlockModalWindowConfig(blockKey, modalWindowKey) {
        const role = this.getRoleOrThrow();
        return (0, ConfigResolver_1.resolveModalWindowConfig)(this.getBlockModalWindowConfigurations(blockKey, role), modalWindowKey);
    }
    /**
     * Метод для получения Record кнопок модального окна блока
     * Должен быть переопределен в наследниках, если блок имеет модальные окна
     * По умолчанию возвращает null
     * @param blockKey - ключ блока
     * @param modalWindowKey - ключ модального окна
     */
    getBlockModalWindowButtons(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record полей для загрузки файлов модального окна блока
     * Должен быть переопределен в наследниках, если блок имеет модальные окна
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowFileFields(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record полей ввода модального окна блока
     * Должен быть переопределен в наследниках, если блок имеет модальные окна
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowTextFields(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record DaData полей модального окна блока
     * Должен быть переопределен в наследниках, если блок имеет модальные окна с DaData полями
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowDaDataFields(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record radiobutton модального окна блока
     * Должен быть переопределен в наследниках, если модальное окно имеет вариативное содержание
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowRadioButtons(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record чекбоксов модального окна блока
     * Должен быть переопределен в наследниках, если модальное окно имеет чекбоксы
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowCheckboxes(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record слайдеров модального окна блока
     * Должен быть переопределен в наследниках, если модальное окно имеет кнопки-слайдеры
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowSliders(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record кнопок toggle модального окна блока
     * Должен быть переопределен в наследниках, если модальное окно имеет кнопки toogle
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowToggleButtons(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
     * Метод для получения Record combobox полей модального окна блока
     * Должен быть переопределен в наследниках, если модальное окно имеет combobox поля
     * По умолчанию возвращает null
     * @param _blockKey - ключ блока
     * @param _modalWindowKey - ключ модального окна
     */
    getBlockModalWindowComboboxFields(_blockKey, _modalWindowKey) {
        return null;
    }
    /**
    * Получает ключ тела блока из ключа блока
    * Должен быть переопределен в наследниках для маппинга blockKey -> blockBodyKey
    * @param blockKey - ключ блока
    * @returns ключ тела блока
    */
    getBlockBodyKey(blockKey) {
        // По умолчанию используем blockKey с суффиксом 'Block'
        return `${blockKey}Block`;
    }
    /**
    * Собирает все локаторы полей формы инлайн-блока (не в модальном окне)
    *
    * @param blockKey - ключ блока
    * @returns объект локаторов для formHelper.fillFormFields, содержащий все типы полей блока
    *
    * @example
    * ```typescript
    * const locators = card.getBlockFormWithFieldsLocators('userBlock', 'PersonalData');
    * await formHelper.fillFormFields(userData, locators, 'блок пользователя');
    * ```
    */
    getBlockModalWindowFormLocators(blockKey, modalWindowKey) {
        return {
            textFieldsLocators: this.getBlockModalWindowTextFields(blockKey, modalWindowKey),
            comboboxFieldsLocators: this.getBlockModalWindowComboboxFields(blockKey, modalWindowKey),
            fileFieldsLocators: this.getBlockModalWindowFileFields(blockKey, modalWindowKey),
            radioButtonsLocators: this.getBlockModalWindowRadioButtons(blockKey, modalWindowKey),
            checkboxesLocators: this.getBlockModalWindowCheckboxes(blockKey, modalWindowKey),
            toggleButtonsLocators: this.getBlockModalWindowToggleButtons(blockKey, modalWindowKey),
            daDataFieldsLocators: this.getBlockModalWindowDaDataFields(blockKey, modalWindowKey),
            multiComboboxFieldsLocators: this.getBlockModalWindowMultiComboboxFields(blockKey, modalWindowKey)
        };
    }
    getBlockFormWithFieldsLocators(blockKey, inlineFormKey) {
        return {
            textFieldsLocators: this.getBlockTextFields(blockKey, inlineFormKey),
            comboboxFieldsLocators: this.getBlockComboboxFields(blockKey, inlineFormKey),
            fileFieldsLocators: this.getBlockFileFields(blockKey, inlineFormKey),
            radioButtonsLocators: this.getBlockRadioButtons(blockKey, inlineFormKey),
            checkboxesLocators: this.getBlockCheckboxes(blockKey, inlineFormKey),
            toggleButtonsLocators: this.getBlockToggleButtons(blockKey, inlineFormKey),
            daDataFieldsLocators: this.getBlockDaDataFields(blockKey, inlineFormKey),
            multiComboboxFieldsLocators: this.getBlockMultiComboboxFields(blockKey, inlineFormKey),
        };
    }
    async goToBlock(blockKey) {
        const blockLocator = this.BlockBodies[blockKey];
        if (!blockLocator) {
            throw new Error(`Блок с ключом "${blockKey}" не найден в BlockBodies`);
        }
        logger_1.logger.info(`Переход к блоку ${blockKey}`, `${this.constructor.name}.goToBlock`);
        await test_1.test.step(`Переход к блоку "${blockKey}"`, async () => {
            await this.scrollToElement(blockLocator);
            try {
                await (0, test_1.expect)(blockLocator).toBeVisible({ timeout: (0, timeouts_1.getTimeouts)().EXPECT });
            }
            catch (error) {
                throw new Error(`Не удалось найти блок "${blockKey}"`);
            }
        });
        logger_1.logger.info(`Переход к блок "${blockKey}" выполнен успешно`, `${this.constructor.name}.goToBlock`);
    }
    /**
    * Метод для проверки видимости конкретного блока с его заголовком на странице
    */
    async checkBlockIsVisible(titleKey, blockName) {
        logger_1.logger.debug(`Проверка видимости блока: ${titleKey}`, `${this.constructor.name}.checkBlockIsVisible`);
        await test_1.test.step(`Проверка видимости блока ${blockName}`, async () => {
            await test_1.expect.soft(this.BlockBodies[blockName]).toBeVisible();
        });
    }
    /**
     * Проверяет видимость кнопок блока в зависимости от роли и контекста.
     */
    async checkBlockButtons(blockKey, context) {
        const role = this.getRoleOrThrow();
        this.validateBlockParams(blockKey, role);
        const config = this.getBlockConfiguration(blockKey, role, context);
        const buttons = this.getBlockButtons(blockKey);
        if (!config) {
            logger_1.logger.warn(`Конфигурация для блока ${blockKey} не найдена`, `${this.constructor.name}.checkBlockButtons`);
            return;
        }
        if (!buttons) {
            logger_1.logger.warn(`Кнопки для блока ${blockKey} не найдены`, `${this.constructor.name}.checkBlockButtons`);
            return;
        }
        await this.visibilityChecker.checkElementsVisibility({
            locators: buttons,
            visibleKeys: config.buttons,
            hiddenKeys: config.notVisibleButtons,
            logContext: `${this.constructor.name}.checkBlockButtons`,
            stepTitle: `Проверка отображения кнопок в блоке ${blockKey}`,
            elementLabel: `кнопки блока ${blockKey}`,
        });
    }
    /**
     * Проверяет кликабельность всех элементов навигации на странице.
     */
    async checkAllNavigationsElementsIsClickable(blockKey) {
        const role = this.getRoleOrThrow();
        this.validateBlockParams(blockKey, role);
        const config = this.getNavigationBlockConfiguration(blockKey, role);
        const navigationElements = this.getNavigationElements(blockKey);
        if (!config) {
            throw new Error('Конфигурации блока навигации не существует');
        }
        if (!navigationElements) {
            logger_1.logger.warn(`Элементы навигации для блока ${blockKey} не найдены`, `${this.constructor.name}.checkAllNavigationsElementsIsClickable`);
            return;
        }
        await this.visibilityChecker.checkElementsVisibility({
            locators: navigationElements,
            visibleKeys: config.navigationElements,
            hiddenKeys: config.notVisibleNavigationElements,
            logContext: `${this.constructor.name}.checkAllNavigationsElementsIsClickable`,
            stepTitle: `Проверка элементов навигации блока ${blockKey}`,
            elementLabel: 'элементы навигации',
            checkEnabled: true,
        });
    }
    /**
     * Проверяет видимость полей-фильтров блока (text / combobox / daData) в зависимости от роли и контекста.
     * Локаторы берутся из {@link getBlockTextFilters},
     * {@link getBlockComboboxFilters}, {@link getBlockDaDataFilters}.
     * Если в конфигурации нет фильтров или нет локаторов — проверка пропускается (warn).
     * @param blockKey — ключ блока карточки
     * @param context — опциональный контекст блока (например Single/Multi)
     * @throws {Error} Если конфигурация блока отсутствует
     */
    async checkBlockFilters(blockKey, context) {
        const role = this.getRoleOrThrow();
        this.validateBlockParams(blockKey, role);
        const config = this.getBlockConfiguration(blockKey, role, context);
        const logContext = `${this.constructor.name}.checkBlockFilters`;
        if (!config) {
            throw new Error('Конфигурации блока навигации не существует');
        }
        if (!visibility_1.FilterVisibilityUtils.hasAnyConfiguredFilters(config)) {
            logger_1.logger.warn(`Для блока ${blockKey} фильтры в конфигурации не заданы — проверка пропущена`, logContext);
            return;
        }
        const groups = visibility_1.FilterVisibilityUtils.buildGroups(config, {
            text: this.getBlockTextFilters(blockKey),
            combobox: this.getBlockComboboxFilters(blockKey),
            daData: this.getBlockDaDataFilters(blockKey),
        });
        const hasAnyLocators = groups.some((group) => group.locators);
        if (!hasAnyLocators) {
            logger_1.logger.warn(`Поля-фильтры для блока ${blockKey} не найдены`, logContext);
            return;
        }
        const checkedGroups = await visibility_1.FilterVisibilityUtils.checkGroups(this.visibilityChecker, groups, {
            logContext,
            stepTitlePrefix: `Проверка отображения полей-фильтров в блоке ${blockKey}`,
        });
        if (checkedGroups === 0) {
            logger_1.logger.warn(`Поля-фильтры для блока ${blockKey} не найдены`, logContext);
        }
    }
    /**
     * Проверяет все элементы блока (кнопки, поля) в зависимости от роли и контекста.
     */
    async checkAllBlockElements(blockKey, context) {
        const role = this.getRoleOrThrow();
        this.validateBlockParams(blockKey, role);
        test_1.test.step(`Проверка видимости всех элементов блока ${blockKey}`, async () => {
            logger_1.logger.info(`Проверка всех элементов блока ${blockKey} для роли ${role}`, `${this.constructor.name}.checkAllBlockElements`);
            // Параллельный запуск
            await Promise.all([
                this.checkBlockButtons(blockKey, context),
                this.checkBlockFilters(blockKey, context)
            ]);
            logger_1.logger.info(`Проверка всех элементов блока ${blockKey} завершена успешно`, `${this.constructor.name}.checkAllBlockElements`);
        });
    }
    /**
    * Открывает модальное окно блока по кнопке-триггеру
    *
    * @param blockKey - ключ блока, содержащего кнопку открытия модального окна
    * @param modalWindowKey - ключ конфигурации модального окна
    * @throws {Error} Если кнопка не найдена, модальное окно не открылось или обнаружена ошибка валидации
    */
    async openBlockModalWindow(blockKey, modalWindowKey) {
        const modalConfig = this.findBlockModalWindowConfig(blockKey, modalWindowKey);
        const blockButtons = this.getBlockButtons(blockKey);
        if (!blockButtons) {
            throw new Error('Кнопки блока не были найдены!');
        }
        const triggerButton = blockButtons[modalConfig.triggerButtonKey];
        await this.modalWindowService.openModal({
            triggerButton,
            modalDialog: this.modalDialog,
            stepTitle: 'Открытие модального окна блока',
        }, this.constructor.name);
    }
    /**
     * Проверяет наличие необходимых колонок в таблице блока по их названиям
     * @param tableLabel - метка таблицы для getByLabel (например, 'Сертификаты пользователя')
     * @param columnNames - массив названий колонок для проверки (например, ['Организация', 'Серийный номер'])
     */
    async verifyRequiredColumnsInBlock(tableLabel, columnNames) {
        this.validateTableLabel(tableLabel);
        if (!Array.isArray(columnNames) || columnNames.length === 0) {
            throw new Error(`columnNames должен быть непустым массивом. Получено: ${JSON.stringify(columnNames)}`);
        }
        logger_1.logger.debug(`Проверка наличия необходимых колонок в таблице "${tableLabel}": ${columnNames.join(', ')}`, `${this.constructor.name}.verifyRequiredColumnsInBlock`);
        await test_1.test.step(`Проверка колонок блока ${tableLabel}`, async () => {
            for (const columnName of columnNames) {
                await test_1.test.step(`Проверка колонки "${columnName}"`, async () => {
                    logger_1.logger.debug(`Проверка колонки "${columnName}" в таблице "${tableLabel}"`, `${this.constructor.name}.verifyRequiredColumnsInBlock`);
                    const columnHeader = this.page.getByLabel(tableLabel).getByRole('columnheader', { name: columnName, exact: true });
                    await test_1.expect.soft(columnHeader).toBeVisible({ timeout: (0, timeouts_1.getTimeouts)().ACTION });
                });
            }
        });
        logger_1.logger.info(`Проверка колонок в таблице "${tableLabel}" завершена. Проверено колонок: ${columnNames.length}`, `${this.constructor.name}.verifyRequiredColumnsInBlock`);
    }
    /**
     * Находит строку в таблице блока по ключевому полю
     * @param rowKey - ключевое поле строки (уникальный идентификатор строки в таблице)
     * @param rowData - объект с данными строки, где ключ - название колонки, значение - ожидаемое значение ячейки
     *                  Например: { 'Организация': 'ООО "Компания"', 'Серийный номер': '1234567890' }
     * @param tableLabel - метка таблицы для getByLabel (например, 'Сертификаты пользователя')
     * @param isNewlyAdded - если true, проверяет только что добавленную строку (первую после заголовка)
     *                      если false, ищет строку по всей таблице; при нескольких совпадениях возвращается последняя
     * @returns Locator строки или null, если строка не найдена
     */
    async findTableRowInBlock(rowKey, keyValue, tableLabel, isNewlyAdded) {
        return this.tableRowService.findTableRow((0, table_scope_1.blockTableScope)(tableLabel), rowKey, keyValue, isNewlyAdded, this.constructor.name);
    }
    /**
    * Кликает по ссылке в найденной строке таблицы блока
    * @param key - объект с ключом и значением для поиска строки
    * @param itemToClick - кликабельный текст в строке таблицы
    * @param tableLabel - метка таблицы для getByLabel (например, 'Сертификаты пользователя')
    * @param isNewlyAdded - если true, ищет среди только что добавленных строк (первая после заголовка)
    * @throws {Error} Если строка не найдена или в строке нет ссылок для клика
    */
    async clickInBlockTableRow(key, itemToClick, tableLabel, isNewlyAdded) {
        await this.tableRowService.clickInTableRow((0, table_scope_1.blockTableScope)(tableLabel), key, itemToClick, isNewlyAdded, this.constructor.name);
    }
    async forEachRow(tableLabel, callback) {
        await this.tableRowService.forEachRow((0, table_scope_1.blockTableScope)(tableLabel), callback, this.constructor.name);
    }
    /**
     * Ищет строку в таблице блока без выброса ошибки (для проверки отсутствия строки)
     * @param rowKey - ключевое поле строки
     * @param rowData - объект с данными строки
     * @param tableLabel - метка таблицы для getByLabel
     * @returns Locator строки или null, если строка не найдена
     */
    async findTableRowInBlockSilent(rowKey, keyValue, tableLabel) {
        return this.tableRowService.findTableRowSilent((0, table_scope_1.blockTableScope)(tableLabel), rowKey, keyValue, this.constructor.name);
    }
    /**
     * Проверяет строку в таблице блока
     * @param rowKey - ключевое поле строки (уникальный идентификатор строки в таблице)
     * @param rowData - объект с данными строки, где ключ - название колонки, значение - ожидаемое значение ячейки
     * @param tableLabel - метка таблицы для getByLabel (например, 'Сертификаты пользователя')
     * @param isNewlyAdded - если true, проверяет только что добавленную строку
     * @param onRowFound - Колбэк, который вызывается после нахождения строки (вызывается даже при ошибках проверки). Применим для очистки мусора в случае падения теста
     */
    async verifyTableRowInBlock(rowKey, rowData, tableLabel, isNewlyAdded, onRowFound) {
        this.validateTableLabel(tableLabel);
        await this.tableRowService.verifyTableRow((0, table_scope_1.blockTableScope)(tableLabel), rowKey, rowData, isNewlyAdded, this.constructor.name, onRowFound);
    }
    /**
     * Заполняет поля инлайн-формы блока.
     * @param blockKey - ключ блока
     * @param inlineFormKey - ключ инлайн-формы
     * @param formFields - объект с полями и данными для заполнения
     */
    async fillInlineBlockForm(blockKey, inlineFormKey, formFields) {
        await this.cardBlockFormService.fillInlineBlockForm(blockKey, inlineFormKey, formFields);
    }
    /**
     * Открывает модальное окно блока, заполняет форму и сохраняет.
     * @param blockKey — ключ блока
     * @param modalWindowKey — ключ конфигурации модального окна
     * @param formFields — данные для заполнения полей формы
     * @throws {Error} Если не удается открыть модалку, заполнить форму или сохранить
     */
    async fillBlockModalForm(blockKey, modalWindowKey, formFields) {
        await this.cardBlockFormService.fillBlockModalForm(blockKey, modalWindowKey, formFields);
    }
    /**
     * Заполняет поля уже открытой модальной формы блока (без open/save).
     */
    async fillOpenBlockModalFormFields(blockKey, modalWindowKey, formFields) {
        await this.cardBlockFormService.fillOpenBlockModalFormFields(blockKey, modalWindowKey, formFields);
    }
    /**
    * Переключает состояние редактирования блока
    *
    * @param blockKey - Ключ блока
    * @param targetState - Целевое состояние: 'editable' (редактирование) или 'notEditable' (просмотр)
    * @param buttonKeys - Кастомные названия кнопок
    * @param logContext - Контекст для логирования
    *
    * @throws {Error} Если не найдены необходимые кнопки
    * @throws {Error} Если не удалось переключить состояние
    *
    * @example
    * // Переключение в режим редактирования
    * await switchBlockEditableState('userBlock', 'editable');
    *
    * @example
    * // Выход из режима редактирования
    * await switchBlockEditableState('userBlock', 'notEditable');
    */
    async switchBlockEditableState(blockKey, targetState, buttonKeys, logContext = 'BaseCard.switchBlockEditableState') {
        await this.cardBlockFormService.switchBlockEditableState(blockKey, targetState, buttonKeys, logContext);
    }
    /**
    * Проверяет состояние полей формы в блоке (доступны для редактирования или нет)
    *
    * @param blockConfig - Конфигурация блока с описанием полей
    * @param blockFormLocators - Локаторы полей формы блока
    * @param mode - Режим проверки:
    *   - 'editable' - поля должны быть доступны для редактирования
    *   - 'notEditable' - поля должны быть только для чтения (недоступны для редактирования)
    *
    * @example
    * // Проверка, что поля в режиме просмотра (только чтение)
    * await checkFormFieldsState(blockConfig, blockFormLocators, 'notEditable');
    *
    * @example
    * // Проверка, что поля доступны для редактирования
    * await checkFormFieldsState(blockConfig, blockFormLocators, 'editable');
    *
    * @remarks
    * Метод проверяет все типы полей, указанные в конфигурации:
    * textFields, comboboxFields, fileFields, radioButtons, checkboxes,
    * toggleButtons, daDataFields, multiComboboxFields
    */
    async checkFormFieldsState(blockConfig, blockFormLocators, mode) {
        await this.cardBlockFormService.checkFormFieldsState(blockConfig, blockFormLocators, mode);
    }
    /**
    * Проверяет значения полей формы в инлайн-блоке
    *
    * @param blockKey - Ключ блока
    * @param inlineFormKey - Ключ инлайн-формы (из конфигурации блока)
    * @param expectedFieldsValues - Объект с ожидаемыми значениями полей
    * @param expectedFieldsValues.textFields - Текстовые поля (key: значение)
    * @param expectedFieldsValues.comboboxFields - Выпадающие списки (key: значение)
    * @param expectedFieldsValues.fileFields - Поля загрузки файлов (key: имя файла)
    * @param expectedFieldsValues.radioButtons - Массив ключей выбранных радио-кнопок
    * @param expectedFieldsValues.checkboxes - Чекбоксы (key: true/false)
    * @param expectedFieldsValues.toggleButtons - Toggle-кнопки (key: true/false/'Yes'/'No')
    * @param expectedFieldsValues.daDataFields - DaData поля (key: значение)
    * @param expectedFieldsValues.multiComboboxFields - Мульти-выпадающие списки (key: массив значений)
    * @param logContext - Контекст для логирования
    *
    * @example
    * // Проверка текстовых полей и чекбоксов
    * await checkInlineBlockFormValues('userBlock', 'PersonalData', {
    *   textFields: { 'name': 'Иван', 'email': 'ivan@mail.ru' },
    *   checkboxes: { 'agree': true }
    * });
    */
    async checkInlineBlockFormValues(blockKey, inlineFormKey, expectedFieldsValues, logContext = 'BaseCard.checkInlineBlockFormValues') {
        await this.cardBlockFormService.checkInlineBlockFormValues(blockKey, inlineFormKey, expectedFieldsValues, logContext);
    }
    /**
     * Универсальный метод для выполнения действия со строкой в блоке.
     * @param blockKey - ключ блока
     * @param rowLocator - локатор строки в блоке
     * @param actionKey - ключ действия (например, 'MenuItemEdit' или 'ButtonEdit')
     */
    async clickRowAction(blockKey, rowLocator, actionKey) {
        await this.cardBlockRowActionsService.clickRowAction(blockKey, rowLocator, actionKey, this.constructor.name);
    }
    /**
     * Проверяет видимость кнопок действий строки в блоке.
     * @param blockKey - ключ блока
     * @param rowLocator - локатор строки в блоке
     */
    async checkGridRowActions(blockKey, rowLocator) {
        await this.cardBlockRowActionsService.checkGridRowActions(blockKey, rowLocator, this.constructor.name);
    }
    /**
     * Открывает строку на редактирование в блоке.
     * @param blockKey - ключ блока
     * @param rowLocator - локатор строки в блоке
     * @returns true если модальное окно успешно открыто
     */
    async editRow(blockKey, rowLocator) {
        return this.cardBlockRowActionsService.editRow(blockKey, rowLocator, this.constructor.name);
    }
    /**
     * Открывает строку на просмотр (readonly) в блоке.
     * @param blockKey - ключ блока
     * @param rowLocator - локатор строки в блоке
     * @returns true если модальное окно успешно открыто
     */
    async viewRow(blockKey, rowLocator) {
        return this.cardBlockRowActionsService.viewRow(blockKey, rowLocator, this.constructor.name);
    }
    /**
     * Удаляет строку в блоке (с подтверждением, если требуется).
     * @param blockKey - ключ блока
     * @param rowLocator - локатор строки в блоке
     * @param confirmDelete - нужно ли подтверждение удаления (по умолчанию true)
     * @returns true если удаление успешно
     */
    async deleteRow(blockKey, rowLocator, confirmDelete = true) {
        return this.cardBlockRowActionsService.deleteRow(blockKey, rowLocator, confirmDelete, this.constructor.name);
    }
    /**
     * Удаляет строку в блоке и проверяет, что она исчезла.
     * @param blockKey - ключ блока
     * @param rowKey - ключевое поле строки для поиска
     * @param rowData - данные строки для поиска и проверки отсутствия
     * @param confirmDelete - нужно ли подтверждение удаления (по умолчанию true)
     */
    async deleteRowAndVerify(blockKey, rowKey, rowData, confirmDelete = true) {
        const tableLabel = this.getBlockTableLabel(blockKey);
        const role = this.getRoleOrThrow();
        logger_1.logger.info(`Начало удаления строки с проверкой в блоке ${blockKey} для роли ${role} (rowKey: ${rowKey}, tableLabel: ${tableLabel})`, `${this.constructor.name}.deleteRowAndVerify`);
        await this.rowActionsOrchestrator.deleteRowAndVerifyBase(() => this.findTableRowInBlock(rowKey, rowData[rowKey], tableLabel, false), async (row) => {
            await this.deleteRow(blockKey, row, confirmDelete);
        }, () => this.findTableRowInBlockSilent(rowKey, rowData[rowKey], tableLabel), rowData);
    }
    /**
     * Редактирует строку в блоке с заполнением формы, сохранением и проверкой результата.
     * @param blockKey - ключ блока
     * @param modalWindowKey - ключ модального окна (из конфигурации блока)
     * @param rowLocator - локатор строки в блоке
     * @param expectedRowData - ожидаемые данные после сохранения (для проверки)
     * @param formFields - Объект с полями для заполнения
     * @param onRowVerified - Колбэк, который вызывается после нахождения строки (вызывается даже при ошибках проверки). Применим для очистки мусора в случае падения теста
     */
    async editRowAndVerify(blockKey, modalWindowKey, rowLocator, expectedRowData, formFields, onRowVerified) {
        const role = this.getRoleOrThrow();
        logger_1.logger.info(`Начало редактирования строки с проверкой в блоке ${blockKey} для роли ${role}`, `${this.constructor.name}.editRowAndVerify`);
        const modalConfig = this.findBlockModalWindowConfig(blockKey, modalWindowKey);
        const fieldsToFill = (0, FormDataFilterUtils_1.filterFormFieldsByConfig)(formFields, modalConfig, `${this.constructor.name}.editRowAndVerify`);
        const tableLabel = this.getBlockTableLabel(blockKey);
        const verifyFn = async () => {
            if (tableLabel) {
                const rowKey = Object.keys(expectedRowData)[0];
                await this.verifyTableRowInBlock(rowKey, expectedRowData, tableLabel, false, onRowVerified);
            }
        };
        const getModalButtons = (key) => {
            const modalButtons = this.getBlockModalWindowButtons(blockKey, key);
            if (!modalButtons) {
                throw new Error(`Кнопки модального окна блока ${blockKey} (${key}) не найдены`);
            }
            return modalButtons;
        };
        await this.rowActionsOrchestrator.editRowAndVerifyBase(() => this.editRow(blockKey, rowLocator), modalWindowKey, fieldsToFill, (key) => this.getBlockModalWindowFormLocators(blockKey, key), getModalButtons, modalConfig.saveButtonKey, (btn, name) => this.performModalTerminalActionToCloseModalWindow(btn, name), verifyFn);
    }
    /**
     * Просматривает строку в блоке и проверяет данные.
     * @param blockKey - ключ блока
     * @param modalWindowKey - ключ модального окна
     * @param rowLocator - локатор строки в блоке
     * @param expectedValues - ожидаемые значения полей
     */
    async viewRowAndVerify(blockKey, modalWindowKey, rowLocator, expectedValues) {
        const role = this.getRoleOrThrow();
        logger_1.logger.info(`Начало просмотра строки с проверкой в блоке ${blockKey} для роли ${role}`, `${this.constructor.name}.viewRowAndVerify`);
        const modalConfig = this.findBlockModalWindowConfig(blockKey, modalWindowKey);
        await this.rowActionsOrchestrator.viewRowAndVerifyBase(modalWindowKey, () => this.viewRow(blockKey, rowLocator), expectedValues, (key) => this.getBlockModalWindowFormLocators(blockKey, key), (key) => this.getBlockModalWindowButtons(blockKey, key), modalConfig.closeButtonKey, (btn, name) => this.performModalTerminalActionToCloseModalWindow(btn, name));
    }
    /**
     * Реализация метода активации/деактивации для карточек.
     */
    async toggleActivationForCard(blockKey, rowLocator, action, actionType, requireConfirmation) {
        await this.cardBlockRowActionsService.toggleActivationForCard(blockKey, rowLocator, action, actionType, requireConfirmation, this.constructor.name);
    }
    async deleteTrashInBlockAfterFail(blockKey, rowLocator, confirmDelete) {
        try {
            logger_1.logger.info(`Зачистка мусора после падения теста по ключу строки`, `${this.constructor.name}.deleteTrashAfterFail`);
            const modalIsVisible = await this.modalDialog.isVisible();
            if (modalIsVisible) {
                await this.page.keyboard.press('Escape');
            }
            await this.deleteRow(blockKey, rowLocator, confirmDelete);
            logger_1.logger.info(`Мусор после теста зачищен. Строка удалена`, `${this.constructor.name}.deleteTrashAfterFail`);
        }
        catch (error) {
            logger_1.logger.info(`Мусор не был зачищен, т.к не был найден по ключу`, `${this.constructor.name}.deleteTrashAfterFail`);
        }
    }
}
exports.BaseCard = BaseCard;
