"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getGrid = getGrid;
exports.getGridRows = getGridRows;
exports.assertGridVisible = assertGridVisible;
exports.assertGridRowCount = assertGridRowCount;
exports.assertGridMinimumRowCount = assertGridMinimumRowCount;
exports.assertGridColumnVisible = assertGridColumnVisible;
exports.getGridCellByRowIndex = getGridCellByRowIndex;
exports.getGridCellByRowValue = getGridCellByRowValue;
exports.assertGridCellText = assertGridCellText;
exports.interactWithGridCell = interactWithGridCell;
exports.editGridCell = editGridCell;
exports.sortGridColumn = sortGridColumn;
exports.filterGridColumn = filterGridColumn;
exports.clearGridColumnFilter = clearGridColumnFilter;
exports.extractGridAsJson = extractGridAsJson;
exports.stringifyGridJson = stringifyGridJson;
async function getGrid(page, gridTarget = 0) {
    const grid = typeof gridTarget === 'string'
        ? page.locator(gridTarget).first()
        : page.locator('.ag-root, .ag-root-wrapper').nth(validateIndex(gridTarget, 'grid'));
    if (!await safeIsVisible(grid)) {
        throw new Error(`Grid ${formatGridTarget(gridTarget)} was not found or is not visible.`);
    }
    return grid;
}
async function getGridRows(page, gridTarget = 0) {
    const grid = await getGrid(page, gridTarget);
    return grid.locator('.ag-center-cols-container .ag-row, .ag-body-viewport .ag-row');
}
async function assertGridVisible(page, gridTarget = 0) {
    await getGrid(page, gridTarget);
}
async function assertGridRowCount(page, expectedCount, gridTarget = 0) {
    validateIndex(expectedCount, 'row count');
    const rows = await getGridRows(page, gridTarget);
    const actualCount = await rows.count();
    if (actualCount !== expectedCount) {
        throw new Error(`Expected grid ${formatGridTarget(gridTarget)} to have ${expectedCount} rows but found ${actualCount}.`);
    }
}
async function assertGridMinimumRowCount(page, minimumCount, gridTarget = 0) {
    validateIndex(minimumCount, 'minimum row count');
    const rows = await getGridRows(page, gridTarget);
    const actualCount = await rows.count();
    if (actualCount < minimumCount) {
        throw new Error(`Expected grid ${formatGridTarget(gridTarget)} to have at least ${minimumCount} rows but found ${actualCount}.`);
    }
}
async function assertGridColumnVisible(page, columnName, gridTarget = 0) {
    const header = await findGridHeader(page, columnName, gridTarget);
    if (!header || !await safeIsVisible(header)) {
        throw new Error(`Grid column "${columnName}" was not found or is not visible.`);
    }
}
async function getGridCellByRowIndex(page, rowIndex, columnName, gridTarget = 0) {
    validateIndex(rowIndex, 'row');
    const columnId = await resolveColumnId(page, columnName, gridTarget);
    const rows = await getGridRows(page, gridTarget);
    const rowCount = await rows.count();
    if (rowCount <= rowIndex) {
        throw new Error(`Grid ${formatGridTarget(gridTarget)} row ${rowIndex} was not found. The grid has ${rowCount} rows.`);
    }
    const cell = rows.nth(rowIndex).locator(cellSelector(columnId)).first();
    if (await safeCount(cell) === 0) {
        throw new Error(`Grid cell in row ${rowIndex} and column "${columnName}" was not found.`);
    }
    return cell;
}
async function getGridCellByRowValue(page, match, gridTarget = 0) {
    const lookupColumnId = await resolveColumnId(page, match.lookupColumn, gridTarget);
    const targetColumnId = await resolveColumnId(page, match.targetColumn, gridTarget);
    const row = await findRowByCellValue(page, lookupColumnId, match.lookupColumn, match.lookupValue, gridTarget);
    const cell = row.locator(cellSelector(targetColumnId)).first();
    if (await safeCount(cell) === 0) {
        throw new Error(`Grid cell in row where column "${match.lookupColumn}" is "${match.lookupValue}" and column "${match.targetColumn}" was not found.`);
    }
    return cell;
}
async function assertGridCellText(cell, expectedText, match) {
    const actualText = normalizeText(await cell.innerText());
    const normalizedExpected = normalizeText(expectedText);
    if (match === 'equal' && actualText !== normalizedExpected) {
        throw new Error(`Expected grid cell text to equal "${expectedText}" but found "${actualText}".`);
    }
    if (match === 'contain' && !actualText.includes(normalizedExpected)) {
        throw new Error(`Expected grid cell text to contain "${expectedText}" but found "${actualText}".`);
    }
}
async function interactWithGridCell(cell, clickType) {
    if (clickType === 'doubleClick') {
        await cell.dblclick();
        return;
    }
    if (clickType === 'rightClick') {
        await cell.click({ button: 'right' });
        return;
    }
    await cell.click();
}
async function editGridCell(cell, value) {
    await cell.dblclick();
    await cell.fill(value);
    await cell.press('Enter');
}
async function sortGridColumn(page, columnName, direction, gridTarget = 0) {
    const header = await findGridHeader(page, columnName, gridTarget);
    if (!header) {
        throw new Error(`Grid column "${columnName}" was not found.`);
    }
    const desiredSort = direction === 'ascending' ? 'asc' : 'desc';
    for (let attempt = 0; attempt < 3; attempt += 1) {
        const currentSort = await header.getAttribute('aria-sort').catch(() => null)
            ?? await header.getAttribute('sort').catch(() => null);
        if (currentSort?.toLowerCase().startsWith(desiredSort)) {
            return;
        }
        await header.click();
    }
    throw new Error(`Grid column "${columnName}" could not be sorted ${direction}.`);
}
async function filterGridColumn(page, columnName, value, gridTarget = 0) {
    const header = await findGridHeader(page, columnName, gridTarget);
    if (!header) {
        throw new Error(`Grid column "${columnName}" was not found.`);
    }
    const filterInput = header.locator('input[aria-label*="Filter"], input[placeholder*="Filter"], input').first();
    if (await safeCount(filterInput) === 0) {
        throw new Error(`Grid column "${columnName}" does not expose a filter input.`);
    }
    await filterInput.fill(value);
    await filterInput.press('Enter');
}
async function clearGridColumnFilter(page, columnName, gridTarget = 0) {
    await filterGridColumn(page, columnName, '', gridTarget);
}
async function extractGridAsJson(page, gridTarget = 0) {
    const grid = await getGrid(page, gridTarget);
    if (typeof grid.evaluate !== 'function') {
        return extractGridAsJsonWithLocators(page, gridTarget);
    }
    const evaluatedRows = await grid.evaluate((root) => {
        const normalize = (value) => (value ?? '').replace(/\s+/g, ' ').trim();
        const all = (selector) => queryDeep(root, selector);
        const columns = all('.ag-header-cell[col-id], .ag-header-cell[data-col-id]')
            .map((header) => {
            const id = header.getAttribute('col-id') ?? header.getAttribute('data-col-id') ?? '';
            return {
                id,
                name: normalize(header.innerText || header.textContent) || id
            };
        })
            .filter((column) => column.id);
        if (columns.length === 0) {
            return undefined;
        }
        return all('.ag-center-cols-container .ag-row, .ag-body-viewport .ag-row').map((row) => {
            const item = {};
            for (const column of columns) {
                const cell = queryDeep(row, cellSelectorForBrowser(column.id))[0];
                item[column.name] = cell ? normalize(cell.innerText || cell.textContent) : '';
            }
            return item;
        }).filter((row) => Object.values(row).some((value) => value !== ''));
        function queryDeep(rootElement, selector) {
            const matches = Array.from(rootElement.querySelectorAll(selector));
            if (rootElement.matches(selector)) {
                matches.unshift(rootElement);
            }
            const shadowRoot = rootElement.shadowRoot;
            if (shadowRoot) {
                matches.push(...Array.from(shadowRoot.querySelectorAll(selector)));
                for (const nestedHost of Array.from(shadowRoot.querySelectorAll('*'))) {
                    matches.push(...queryDeep(nestedHost, selector));
                }
            }
            for (const nestedHost of Array.from(rootElement.querySelectorAll('*'))) {
                if (nestedHost.shadowRoot) {
                    matches.push(...queryDeep(nestedHost, selector));
                }
            }
            return Array.from(new Set(matches));
        }
        function cellSelectorForBrowser(columnId) {
            const escapedColumn = columnId.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
            return `.ag-cell[col-id="${escapedColumn}"], .ag-cell[data-col-id="${escapedColumn}"]`;
        }
    });
    if (evaluatedRows) {
        return evaluatedRows;
    }
    return extractGridAsJsonWithLocators(page, gridTarget);
}
async function extractGridAsJsonWithLocators(page, gridTarget = 0) {
    const columns = await getGridColumns(page, gridTarget);
    const rows = await getGridRows(page, gridTarget);
    const rowCount = await rows.count();
    const data = [];
    for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
        const row = rows.nth(rowIndex);
        const item = {};
        for (const column of columns) {
            const cell = row.locator(cellSelector(column.id)).first();
            item[column.name] = await safeCount(cell) > 0 ? normalizeText(await cell.innerText()) : '';
        }
        if (Object.values(item).some((value) => value !== '')) {
            data.push(item);
        }
    }
    return data;
}
function stringifyGridJson(rows) {
    return JSON.stringify(rows, null, 2);
}
async function resolveColumnId(page, columnName, gridTarget) {
    const grid = await getGrid(page, gridTarget);
    const escapedColumn = escapeAttribute(columnName);
    const directCell = grid.locator(cellSelector(columnName)).first();
    if (await safeCount(directCell) > 0) {
        return columnName;
    }
    const header = await findGridHeader(page, columnName, gridTarget);
    const headerColumnId = header
        ? await header.getAttribute('col-id').catch(() => null)
            ?? await header.getAttribute('data-col-id').catch(() => null)
        : null;
    if (headerColumnId) {
        return headerColumnId;
    }
    const matchingHeader = grid.locator(`.ag-header-cell[col-id="${escapedColumn}"], .ag-header-cell[data-col-id="${escapedColumn}"]`).first();
    if (await safeCount(matchingHeader) > 0) {
        return columnName;
    }
    throw new Error(`Grid column "${columnName}" was not found.`);
}
async function getGridColumns(page, gridTarget) {
    const grid = await getGrid(page, gridTarget);
    const headers = grid.locator('.ag-header-cell[col-id], .ag-header-cell[data-col-id]');
    const headerCount = await headers.count();
    const columns = [];
    for (let headerIndex = 0; headerIndex < headerCount; headerIndex += 1) {
        const header = headers.nth(headerIndex);
        const id = await header.getAttribute('col-id').catch(() => null)
            ?? await header.getAttribute('data-col-id').catch(() => null);
        if (!id) {
            continue;
        }
        const name = normalizeText(await header.innerText().catch(() => '')) || id;
        columns.push({ id, name });
    }
    if (columns.length === 0) {
        throw new Error(`Grid ${formatGridTarget(gridTarget)} does not expose any columns.`);
    }
    return columns;
}
async function findGridHeader(page, columnName, gridTarget) {
    const grid = await getGrid(page, gridTarget);
    const escapedText = escapeText(columnName);
    const escapedAttribute = escapeAttribute(columnName);
    const candidates = [
        grid.locator(`.ag-header-cell[col-id="${escapedAttribute}"], .ag-header-cell[data-col-id="${escapedAttribute}"]`).first(),
        grid.locator(`.ag-header-cell:has(.ag-header-cell-text:text-is("${escapedText}"))`).first(),
        grid.locator(`.ag-header-cell:has-text("${escapedText}")`).first()
    ];
    for (const candidate of candidates) {
        if (await safeCount(candidate) > 0) {
            return candidate;
        }
    }
    return undefined;
}
async function findRowByCellValue(page, lookupColumnId, lookupColumnName, lookupValue, gridTarget) {
    const rows = await getGridRows(page, gridTarget);
    const rowCount = await rows.count();
    const normalizedExpected = normalizeText(lookupValue);
    for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
        const row = rows.nth(rowIndex);
        const cell = row.locator(cellSelector(lookupColumnId)).first();
        if (await safeCount(cell) === 0) {
            continue;
        }
        const actualText = normalizeText(await cell.innerText());
        if (actualText === normalizedExpected) {
            return row;
        }
    }
    throw new Error(`Grid row where column "${lookupColumnName}" is "${lookupValue}" was not found.`);
}
function cellSelector(columnId) {
    const escapedColumn = escapeAttribute(columnId);
    return `.ag-cell[col-id="${escapedColumn}"], .ag-cell[data-col-id="${escapedColumn}"]`;
}
function normalizeText(value) {
    return value.replace(/\s+/g, ' ').trim();
}
function validateIndex(value, label) {
    if (!Number.isInteger(value) || value < 0) {
        throw new Error(`Invalid ${label} index "${value}". Index must be a non-negative integer.`);
    }
    return value;
}
function formatGridTarget(gridTarget) {
    return typeof gridTarget === 'string' ? `matching selector "${gridTarget}"` : `${gridTarget}`;
}
async function safeCount(locator) {
    try {
        return await locator.count();
    }
    catch {
        return 0;
    }
}
async function safeIsVisible(locator) {
    try {
        return await locator.isVisible();
    }
    catch {
        return false;
    }
}
function escapeText(value) {
    return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
function escapeAttribute(value) {
    return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
