"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertElementVisibility = assertElementVisibility;
exports.parseVisibility = parseVisibility;
exports.splitValues = splitValues;
/**
 * Checks one or more UI elements against the requested visibility state.
 *
 * Field names, visibility values, and indexes can be comma-separated. A single
 * visibility value is applied to all fields, and missing indexes default to 0.
 */
async function assertElementVisibility(page, fieldNames, visibilities, indexes, selectors) {
    const fields = splitValues(fieldNames);
    if (fields.length === 0) {
        throw new Error('At least one field name must be provided for visibility check.');
    }
    const visibilityValues = expandValues(splitValues(visibilities), fields.length, 'visibility');
    const indexValues = expandValues(indexes == null || indexes.trim() === '' ? ['0'] : splitValues(indexes), fields.length, 'index');
    for (let i = 0; i < fields.length; i += 1) {
        const field = fields[i];
        const expectedVisibility = parseVisibility(visibilityValues[i]);
        const index = parseIndex(indexValues[i]);
        await assertSingleElementVisibility(page, field, expectedVisibility, index, selectors);
    }
}
function parseVisibility(value) {
    const normalized = value.trim().replace(/[\s_-]+/g, '').toLowerCase();
    if (normalized === 'visible') {
        return 'visible';
    }
    if (normalized === 'notvisible' || normalized === 'hidden') {
        return 'notVisible';
    }
    throw new Error(`Unsupported visibility value "${value}". Use "visible" or "notVisible".`);
}
function splitValues(value) {
    return value
        .split(',')
        .map((item) => item.trim())
        .filter((item) => item.length > 0);
}
async function assertSingleElementVisibility(page, fieldName, expectedVisibility, index, selectors) {
    if (expectedVisibility === 'notVisible') {
        const visibleElement = await findVisibleElement(page, fieldName, index, selectors);
        if (!visibleElement) {
            return;
        }
        throw new Error(`Element "${fieldName}" at index ${index} is visible.`);
    }
    const element = await findMatchingElement(page, fieldName, index, true, selectors);
    if (!element) {
        throw new Error(`Element "${fieldName}" at index ${index} is not visible because no matching locator was found.`);
    }
    if (await isActuallyVisible(element)) {
        return;
    }
    throw new Error(`Element "${fieldName}" at index ${index} is not visible.`);
}
async function findMatchingElement(page, fieldName, index, preferVisible, selectors) {
    let firstMatch;
    for (const locator of possibleLocators(page, fieldName, selectors)) {
        const count = await safeCount(locator);
        if (count <= index) {
            continue;
        }
        const candidate = locator.nth(index);
        firstMatch ??= candidate;
        if (!preferVisible || await safeIsVisible(candidate)) {
            return candidate;
        }
    }
    return firstMatch;
}
async function findVisibleElement(page, fieldName, index, selectors) {
    for (const locator of possibleLocators(page, fieldName, selectors)) {
        const count = await safeCount(locator);
        if (count <= index) {
            continue;
        }
        const candidate = locator.nth(index);
        if (await isActuallyVisible(candidate)) {
            return candidate;
        }
    }
    return undefined;
}
function possibleLocators(page, fieldName, selectors) {
    const escapedText = escapeText(fieldName);
    const escapedCss = cssEscape(fieldName);
    const selector = selectors?.[fieldName];
    return [
        ...(selector ? [page.locator(selector)] : []),
        page.getByLabel(fieldName),
        page.getByText(fieldName, { exact: true }),
        page.locator(`label-cr:has-text("${escapedText}")`),
        page.locator(`label:has-text("${escapedText}")`),
        page.locator(`span.ag-header-cell-text:has-text("${escapedText}")`),
        page.locator(`div.ag-header-cell:has-text("${escapedText}")`),
        page.locator(`[data-test-id="${escapeAttribute(fieldName)}"]`),
        page.locator(`[name="${escapeAttribute(fieldName)}"]`),
        page.locator(`[aria-label="${escapeAttribute(fieldName)}"]`),
        page.locator(`[col-id="${escapeAttribute(fieldName)}"]`),
        page.locator(`[row-id="${escapeAttribute(fieldName)}"]`),
        page.locator(`#${escapedCss}`),
        page.locator(`.${escapedCss}`)
    ];
}
function expandValues(values, expectedLength, label) {
    if (values.length === 0) {
        throw new Error(`At least one ${label} value must be provided.`);
    }
    if (values.length === 1) {
        return Array(expectedLength).fill(values[0]);
    }
    if (values.length !== expectedLength) {
        throw new Error(`Expected ${expectedLength} ${label} values but received ${values.length}.`);
    }
    return values;
}
function parseIndex(value) {
    const parsed = Number.parseInt(value, 10);
    if (!Number.isInteger(parsed) || parsed < 0) {
        throw new Error(`Invalid index "${value}". Index must be a non-negative integer.`);
    }
    return parsed;
}
async function safeCount(locator) {
    try {
        return await locator.count();
    }
    catch {
        return 0;
    }
}
async function safeIsVisible(locator) {
    try {
        return await locator.isVisible();
    }
    catch {
        return false;
    }
}
async function isActuallyVisible(locator) {
    const visible = await safeIsVisible(locator);
    if (!visible) {
        return false;
    }
    return !await isHiddenByAttributes(locator);
}
async function isHiddenByAttributes(locator) {
    try {
        return Boolean(await locator.evaluate((element) => {
            const style = window.getComputedStyle(element);
            const parentStyle = element.parentElement ? window.getComputedStyle(element.parentElement) : undefined;
            return element.hasAttribute('hidden')
                || element.getAttribute('hidden') === 'true'
                || element.classList.contains('dnone')
                || element.classList.contains('inactive-tab')
                || style.display === 'none'
                || style.visibility === 'hidden'
                || Boolean(element.parentElement && (element.parentElement.hasAttribute('hidden')
                    || element.parentElement.getAttribute('hidden') === 'true'
                    || element.parentElement.classList.contains('dnone')
                    || element.parentElement.classList.contains('inactive-tab')
                    || parentStyle?.display === 'none'
                    || parentStyle?.visibility === 'hidden'));
        }));
    }
    catch {
        return false;
    }
}
function escapeText(value) {
    return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
function escapeAttribute(value) {
    return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
function cssEscape(value) {
    return value.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, '\\$1').replace(/\s/g, '\\ ');
}
