"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GridRowService = void 0;
const test_1 = require("@playwright/test");
const timeouts_1 = require("../../../timeouts");
const logger_1 = require("../../../utils/logger");
const TableRowUtils_1 = require("../../BasePage/utils/TableRowUtils");
/**
 * Сервис для работы со строками таблицы в грид-страницах.
 * Инкапсулирует поиск строк, проверку содержимого и базовые проверки колонок.
 */
class GridRowService {
    constructor(page, textUtils) {
        this.page = page;
        this.textUtils = textUtils;
    }
    /**
     * Проверяет наличие обязательных колонок по их названиям.
     */
    async verifyRequiredColumns(columnNames, logContext) {
        if (!Array.isArray(columnNames) || columnNames.length === 0) {
            throw new Error(`columnNames должен быть непустым массивом. Получено: ${JSON.stringify(columnNames)}`);
        }
        logger_1.logger.debug(`Проверка наличия необходимых колонок: ${columnNames.join(', ')}`, `${logContext}.verifyRequiredColumns`);
        await test_1.test.step(`Проверка наличия колонок грида`, async () => {
            for (const columnName of columnNames) {
                await test_1.expect
                    .soft(this.page.getByRole('columnheader', { name: columnName, exact: true }))
                    .toBeVisible({ timeout: timeouts_1.TIMEOUTS.EXPECT });
            }
        });
        logger_1.logger.info(`Проверка колонок завершена. Проверено колонок: ${columnNames.length}`, `${logContext}.verifyRequiredColumns`);
    }
    /**
     * Поиск новой строки (первая строка после заголовка).
     */
    async findNewRow(keyValue, keyColumnIndex, rowData, logContext) {
        logger_1.logger.debug('Поиск новой строки', `${logContext}.findTableRow`);
        let foundRow = null;
        await test_1.expect
            .poll(async () => {
            const currentRows = this.page.getByRole('row');
            const currentRowCount = await currentRows.count();
            if (currentRowCount < 2) {
                logger_1.logger.debug('Таблица еще не обновилась, ждем...', `${logContext}.findTableRow`);
                foundRow = null;
                return false;
            }
            const row = currentRows.nth(1); // 0 — header
            if (await (0, TableRowUtils_1.checkRowMatch)(row, keyValue, keyColumnIndex, this.textUtils, `${logContext}.findTableRow`)) {
                logger_1.logger.debug(`Новая строка найдена → ${JSON.stringify(rowData)}`, `${logContext}.findTableRow`);
                foundRow = row;
                return true;
            }
            foundRow = null;
            return false;
        }, {
            message: `Новая строка не найдена → ${JSON.stringify(rowData)}`,
            timeout: timeouts_1.TIMEOUTS.TABLE_UPDATE,
            intervals: [1000, 1000, 2000, 3000, 3000, 5000]
        })
            .toBeTruthy();
        return foundRow;
    }
    /**
     * Поиск по всей таблице. Возвращает последнее совпадение по ключу.
     * После появления строки делается пауза стабилизации (таблица может перестроить порядок),
     * затем повторный скан — чтобы вернуть строку в итоговой позиции, а не в момент первого появления.
     */
    async findExistingRow(keyValue, keyColumnIndex, rowData, logContext) {
        logger_1.logger.debug('Поиск существующей строки', `${logContext}.findTableRow`);
        await test_1.expect
            .poll(async () => {
            const currentRows = this.page.getByRole('row');
            const currentRowCount = await currentRows.count();
            if (currentRowCount < 2) {
                logger_1.logger.debug('Таблица еще не обновилась, ждем...', `${logContext}.findTableRow`);
                return false;
            }
            for (let i = 1; i < currentRowCount; i++) {
                const row = currentRows.nth(i);
                if (await (0, TableRowUtils_1.checkRowMatch)(row, keyValue, keyColumnIndex, this.textUtils, `${logContext}.findTableRow`)) {
                    return true;
                }
            }
            return false;
        }, {
            message: `Строка не найдена в таблице → ${JSON.stringify(rowData)}`,
            timeout: timeouts_1.TIMEOUTS.TABLE_UPDATE,
            intervals: [1000, 1000, 2000, 3000, 3000, 5000]
        })
            .toBeTruthy();
        // Пауза стабилизации
        await this.page.waitForTimeout(timeouts_1.TIMEOUTS.SHORT_WAIT);
        const allRows = this.page.getByRole('row');
        const rowCount = await allRows.count();
        let lastMatch = null;
        for (let i = 1; i < rowCount; i++) {
            const row = allRows.nth(i);
            if (await (0, TableRowUtils_1.checkRowMatch)(row, keyValue, keyColumnIndex, this.textUtils, `${logContext}.findTableRow`)) {
                lastMatch = row;
            }
        }
        if (lastMatch) {
            logger_1.logger.debug(`Строка найдена в таблице → ${JSON.stringify(rowData)}`, `${logContext}.findTableRow`);
            return lastMatch;
        }
        throw new Error(`Строка найдена при опросе таблицы, но после стабилизации не найдена при повторном скане → ${JSON.stringify(rowData)}`);
    }
    /**
     * Поиск строки по rowKey.
     */
    async findTableRow(rowKey, rowData, isNewlyAdded, logContext) {
        logger_1.logger.info(`Поиск строки в таблице (rowKey: ${rowKey}, isNewlyAdded: ${isNewlyAdded})`, `${logContext}.findTableRow`);
        const keyValue = this.textUtils.normalizeTextForComparison(rowData[rowKey] ?? '');
        if (!keyValue) {
            logger_1.logger.error(`rowKey "${rowKey}" имеет пустое значение`, `${logContext}.findTableRow`);
            throw new Error(`rowKey "${rowKey}" имеет пустое значение`);
        }
        // Ждем, пока таблица обновится и появятся строки
        const rows = this.page.getByRole('row');
        await test_1.expect
            .poll(async () => {
            const currentRowCount = await rows.count();
            if (currentRowCount < 2) {
                logger_1.logger.debug('Таблица еще не обновилась, ждем появления строк...', `${logContext}.findTableRow`);
                return false;
            }
            return true;
        }, {
            message: 'В таблице нет строк для поиска',
            timeout: timeouts_1.TIMEOUTS.TABLE_UPDATE,
            intervals: [1000, 1000, 2000, 3000, 3000, 5000]
        })
            .toBeTruthy();
        // КЕШИРОВАНИЕ: Получаем структуру таблицы
        const columnIndexes = await (0, TableRowUtils_1.getCachedTableStructure)(this.page, this.textUtils);
        const keyColumnIndex = (0, TableRowUtils_1.getColumnIndex)(columnIndexes, rowKey, this.textUtils);
        if (keyColumnIndex === undefined) {
            logger_1.logger.error(`Колонка "${rowKey}" не найдена в таблице для поиска строки`, `${logContext}.findTableRow`);
            throw new Error(`Колонка "${rowKey}" не найдена в таблице для поиска строки`);
        }
        const finalKeyColumnIndex = keyColumnIndex;
        if (isNewlyAdded) {
            return this.findNewRow(keyValue, finalKeyColumnIndex, rowData, logContext);
        }
        return this.findExistingRow(keyValue, finalKeyColumnIndex, rowData, logContext);
    }
    /**
     * Тихий поиск строки в таблице без выброса ошибок.
     */
    async findTableRowSilent(rowKey, rowData, logContext) {
        logger_1.logger.debug(`Тихий поиск строки в таблице (rowKey: ${rowKey})`, `${logContext}.findTableRowSilent`);
        const keyValue = this.textUtils.normalizeTextForComparison(rowData[rowKey] ?? '');
        if (!keyValue) {
            logger_1.logger.debug(`rowKey "${rowKey}" имеет пустое значение, возвращаем null`, `${logContext}.findTableRowSilent`);
            return null;
        }
        const rows = this.page.getByRole('row');
        const rowCount = await rows.count();
        // Если в таблице нет строк данных (только заголовок или пусто), возвращаем null
        if (rowCount < 2) {
            logger_1.logger.debug('В таблице нет строк для поиска, возвращаем null', `${logContext}.findTableRowSilent`);
            return null;
        }
        const columnIndexes = await (0, TableRowUtils_1.getCachedTableStructure)(this.page, this.textUtils);
        const keyColumnIndex = (0, TableRowUtils_1.getColumnIndex)(columnIndexes, rowKey, this.textUtils);
        if (keyColumnIndex === undefined) {
            logger_1.logger.debug(`Колонка "${rowKey}" не найдена в таблице, возвращаем null`, `${logContext}.findTableRowSilent`);
            return null;
        }
        logger_1.logger.debug(`Поиск строки по всей таблице (${rowCount - 1} строк)`, `${logContext}.findTableRowSilent`);
        for (let i = 1; i < rowCount; i++) {
            const row = rows.nth(i);
            if (await (0, TableRowUtils_1.checkRowMatch)(row, keyValue, keyColumnIndex, this.textUtils, `${logContext}.findTableRowSilent`)) {
                logger_1.logger.debug(`Строка найдена в строке ${i} → ${JSON.stringify(rowData)}`, `${logContext}.findTableRowSilent`);
                return row;
            }
        }
        logger_1.logger.debug(`Строка не найдена в таблице → ${JSON.stringify(rowData)}`, `${logContext}.findTableRowSilent`);
        return null;
    }
    /**
     * Проверка строки в таблице.
     */
    async verifyTableRow(rowKey, rowData, isNewlyAdded, logContext, onRowFound) {
        if (!rowKey || typeof rowKey !== 'string' || rowKey.trim() === '') {
            throw new Error(`rowKey должен быть непустой строкой. Получено: ${rowKey}`);
        }
        if (!rowData || typeof rowData !== 'object' || Object.keys(rowData).length === 0) {
            throw new Error(`rowData должен быть непустым объектом. Получено: ${JSON.stringify(rowData)}`);
        }
        await test_1.test.step(`Проверка строки по ключу "${rowKey}"`, async () => {
            const row = await this.findTableRow(rowKey, rowData, isNewlyAdded, logContext);
            if (!row)
                return;
            // Вызываем колбэк с найденной строкой
            if (onRowFound) {
                onRowFound(row);
            }
            const columnIndexes = await (0, TableRowUtils_1.getCachedTableStructure)(this.page, this.textUtils);
            // Получаем все ячейки строки один раз
            const allCells = await row.getByRole('cell').all();
            // Подготавливаем данные для проверки всех ячеек
            const cellsToVerify = [];
            for (const [columnName, expectedValue] of Object.entries(rowData)) {
                if (!expectedValue)
                    continue;
                const columnIndex = await (0, TableRowUtils_1.resolveColumnIndexForVerify)(columnIndexes, columnName, this.textUtils, `${logContext}.verifyTableRow`);
                if (columnIndex === undefined) {
                    throw new Error(`Колонка "${columnName}" не найдена в таблице`);
                }
                // Проверяем, что индекс не выходит за границы
                if (columnIndex >= allCells.length) {
                    throw new Error(`Индекс колонки ${columnIndex} выходит за границы (всего ячеек: ${allCells.length}) для колонки "${columnName}"`);
                }
                cellsToVerify.push({
                    columnName,
                    expectedValue,
                    columnIndex,
                    cell: allCells[columnIndex]
                });
            }
            // Последовательно проверяем каждую ячейку
            for (const { columnName, expectedValue, cell } of cellsToVerify) {
                await test_1.test.step(`Проверка ячейки "${columnName}" со значением "${expectedValue}"`, async () => {
                    const normalizedExpected = this.textUtils.normalizeTextForComparison(expectedValue);
                    // Ждем видимости ячейки
                    await cell.waitFor({ state: 'visible', timeout: timeouts_1.TIMEOUTS.ACTION });
                    // Используем expect.poll для ожидания обновления текста ячейки
                    await test_1.expect
                        .poll(async () => {
                        // Используем сохраненную ячейку, не ищем заново
                        const actualText = await cell.textContent();
                        const normalizedActual = this.textUtils.normalizeTextForComparison(actualText || '');
                        if (normalizedActual !== normalizedExpected) {
                            logger_1.logger.debug(`Несоответствие в ячейке "${columnName}": ожидалось "${normalizedExpected}", получено "${normalizedActual}")`, `${logContext}.verifyTableRow`);
                        }
                        return normalizedActual === normalizedExpected;
                    }, {
                        message: `Текст ячейки "${columnName}" не соответствует ожидаемому значению "${expectedValue}". Проверьте логи или отчет для деталей.`,
                        timeout: timeouts_1.TIMEOUTS.TABLE_UPDATE,
                        intervals: [1000, 1000, 2000, 3000, 3000, 5000]
                    })
                        .toBeTruthy();
                });
            }
        });
    }
}
exports.GridRowService = GridRowService;
