"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OperateProcessesPage = void 0;
const test_1 = require("@playwright/test");
const sleep_1 = require("../../utils/sleep");
const constants_1 = require("../../utils/constants");
const env_1 = require("../../utils/env");
class OperateProcessesPage {
    page;
    processResultCount;
    processActiveCheckbox;
    processCompletedCheckbox;
    processRunningInstancesCheckbox;
    processIncidentsCheckbox;
    processPageHeading;
    noMatchingInstancesMessage;
    processFinishedInstancesCheckbox;
    moreFiltersButton;
    processInstanceKeyTextBox;
    whatsNewPopUp;
    gotItButton;
    processesTabLink;
    constructor(page) {
        this.page = page;
        this.processResultCount = page.getByTestId('result-count');
        this.processesTabLink = page.getByRole('link', { name: 'Processes' });
        this.processActiveCheckbox = page.locator('input#active');
        this.processCompletedCheckbox = page.locator('input#completed');
        this.processRunningInstancesCheckbox = page
            .getByTestId('filter-running-instances')
            .getByRole('checkbox');
        this.processIncidentsCheckbox = page.locator('input#incidents');
        this.processPageHeading = page
            .getByTestId('expanded-panel')
            .getByRole('heading', { name: 'Process' });
        this.noMatchingInstancesMessage = page.getByText('There are no Instances matching this filter set');
        this.processFinishedInstancesCheckbox = page
            .getByTestId('filter-finished-instances')
            .getByRole('checkbox');
        this.moreFiltersButton = page.getByRole('button', { name: 'More filters' });
        this.processInstanceKeyTextBox = page
            .locator('#processInstanceKey')
            .or(page.locator('#ids'));
        this.whatsNewPopUp = page.getByRole('heading', {
            name: "Here's what moved in Operate",
        });
        this.gotItButton = page.getByRole('button', { name: 'Got it' });
    }
    async checkCheckbox(checkbox) {
        await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
        if (!(await checkbox.isChecked())) {
            // Carbon DS checkboxes are hidden inputs — click the label to trigger React's
            // synthetic event instead of force-checking the hidden input directly, which
            // would be overridden by React's controlled state on the next render.
            const checkboxId = await checkbox.getAttribute('id');
            if (checkboxId) {
                await this.page
                    .locator(`label[for="${checkboxId}"]`)
                    .click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
            }
            else {
                await checkbox.check({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
            }
            await (0, test_1.expect)(checkbox).toBeChecked({
                checked: true,
                timeout: constants_1._1_SECOND_IN_MS * 30,
            });
        }
    }
    async uncheckCheckbox(checkbox) {
        await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
        if (await checkbox.isChecked()) {
            const checkboxId = await checkbox.getAttribute('id');
            if (checkboxId) {
                await this.page
                    .locator(`label[for="${checkboxId}"]`)
                    .click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
            }
            else {
                await checkbox.uncheck({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
            }
            await (0, test_1.expect)(checkbox).toBeChecked({
                checked: false,
                timeout: constants_1._1_SECOND_IN_MS * 30,
            });
        }
    }
    async uncheckCompletedCheckbox() {
        await this.uncheckCheckbox(this.processCompletedCheckbox);
    }
    async uncheckActiveCheckbox() {
        await this.uncheckCheckbox(this.processActiveCheckbox);
    }
    async toggleActiveCheckboxOn() {
        await this.uncheckCompletedCheckbox();
        await this.clickProcessIncidentsCheckbox();
        await this.processActiveCheckbox.waitFor({
            state: 'attached',
            timeout: constants_1._1_SECOND_IN_MS * 10,
        });
        if (await this.processActiveCheckbox.isChecked({ timeout: constants_1._1_SECOND_IN_MS })) {
            await this.uncheckCheckbox(this.processActiveCheckbox);
            await (0, sleep_1.sleep)(200); // Required to skip the debounce protection on the frontend
            await this.checkCheckbox(this.processActiveCheckbox);
        }
        else {
            await this.checkCheckbox(this.processActiveCheckbox);
        }
    }
    async toggleCompletedCheckbox() {
        await this.uncheckActiveCheckbox();
        await this.clickProcessIncidentsCheckbox();
        await this.processCompletedCheckbox.waitFor({
            state: 'attached',
            timeout: constants_1._1_SECOND_IN_MS * 10,
        });
        if (await this.processCompletedCheckbox.isChecked({ timeout: constants_1._1_SECOND_IN_MS })) {
            await this.uncheckCheckbox(this.processCompletedCheckbox);
            await (0, sleep_1.sleep)(200); // Required to skip the debounce protection on the frontend
            await this.checkCheckbox(this.processCompletedCheckbox);
        }
        else {
            await this.checkCheckbox(this.processCompletedCheckbox);
            await (0, sleep_1.sleep)(200);
        }
    }
    async applyProcessStateFilter(type) {
        if (type === 'active') {
            await this.toggleActiveCheckboxOn();
        }
        else {
            await this.toggleCompletedCheckbox();
        }
    }
    async checkTableForProcess(processName) {
        try {
            const processTable = this.page.locator('[aria-label="Process Instances Panel"]');
            await (0, test_1.expect)(processTable).toBeVisible({ timeout: constants_1._1_SECOND_IN_MS * 4 });
            const timeout = env_1.isOpenSearch ? constants_1._1_MINUTE_IN_MS : constants_1._1_SECOND_IN_MS * 20;
            const row = this.page.locator(`tr:has-text("${processName}")`).first();
            await (0, test_1.expect)(row).toBeVisible({ timeout });
            const link = row.locator('a').first();
            await (0, test_1.expect)(link).toBeVisible({ timeout: constants_1._1_SECOND_IN_MS * 2 });
            await link.scrollIntoViewIfNeeded();
            await link.click({ timeout: constants_1._1_SECOND_IN_MS * 2 });
            await (0, test_1.expect)(this.page.getByText('Instance History').first()).toBeVisible({ timeout: constants_1._1_SECOND_IN_MS * 10 });
            if (await this.whatsNewPopUp.isVisible()) {
                await this.gotItButton.click();
            }
            return true;
        }
        catch (err) {
            return false;
        }
    }
    async clickProcessActiveCheckbox() {
        await this.processActiveCheckbox.waitFor({
            state: 'attached',
            timeout: constants_1._1_SECOND_IN_MS * 10,
        });
        if (!(await this.processActiveCheckbox.isChecked())) {
            await this.processActiveCheckbox.check({ force: true, timeout: 120000 });
            await (0, test_1.expect)(this.processActiveCheckbox).toBeChecked({
                checked: true,
                timeout: constants_1._1_SECOND_IN_MS * 5,
            });
        }
    }
    async clickProcessCompletedCheckbox() {
        await this.processCompletedCheckbox.waitFor({
            state: 'attached',
            timeout: constants_1._1_SECOND_IN_MS * 10,
        });
        if (!(await this.processCompletedCheckbox.isChecked())) {
            await this.processCompletedCheckbox.check({ force: true, timeout: 120000 });
            await (0, test_1.expect)(this.processCompletedCheckbox).toBeChecked({
                checked: true,
                timeout: constants_1._1_SECOND_IN_MS * 5,
            });
        }
    }
    async clickProcessIncidentsCheckbox() {
        await this.processIncidentsCheckbox.waitFor({
            state: 'attached',
            timeout: constants_1._1_SECOND_IN_MS * 10,
        });
        const wasChecked = await this.processIncidentsCheckbox.isChecked();
        if (wasChecked) {
            await this.processIncidentsCheckbox.uncheck({
                force: true,
                timeout: 90000,
            });
        }
        else {
            await this.processIncidentsCheckbox.check({ force: true, timeout: 90000 });
        }
        await (0, test_1.expect)(this.processIncidentsCheckbox).toBeChecked({
            checked: !wasChecked,
            timeout: constants_1._1_SECOND_IN_MS * 5,
        });
    }
    async clickRunningProcessInstancesCheckbox() {
        await this.processRunningInstancesCheckbox.waitFor({
            state: 'attached',
            timeout: constants_1._1_SECOND_IN_MS * 10,
        });
        const wasChecked = await this.processRunningInstancesCheckbox.isChecked();
        if (wasChecked) {
            await this.processRunningInstancesCheckbox.uncheck({
                force: true,
                timeout: 90000,
            });
        }
        else {
            await this.processRunningInstancesCheckbox.check({
                force: true,
                timeout: 90000,
            });
        }
        await (0, test_1.expect)(this.processRunningInstancesCheckbox).toBeChecked({
            checked: !wasChecked,
            timeout: constants_1._1_SECOND_IN_MS * 5,
        });
    }
    async clickFinishedProcessInstancesCheckbox() {
        await this.processFinishedInstancesCheckbox.waitFor({
            state: 'visible',
            timeout: constants_1._1_SECOND_IN_MS * 10,
        });
        const wasChecked = await this.processFinishedInstancesCheckbox.isChecked();
        await this.processFinishedInstancesCheckbox.click({ timeout: 90000 });
        await (0, test_1.expect)(this.processFinishedInstancesCheckbox).toBeChecked({
            checked: !wasChecked,
            timeout: constants_1._1_SECOND_IN_MS * 5,
        });
    }
    async clickProcessInstanceLink(processName, type = 'active') {
        await this.applyProcessStateFilter(type);
        if (await this.checkTableForProcess(processName)) {
            return;
        }
        const MAX_ATTEMPTS = 30;
        const TOTAL_TIMEOUT_MS = env_1.isOpenSearch
            ? constants_1._1_MINUTE_IN_MS * 10
            : constants_1._1_MINUTE_IN_MS * 6;
        let attempt = 0;
        let lastError;
        const startTime = Date.now();
        const operateUrl = this.page.url();
        while (Date.now() - startTime < TOTAL_TIMEOUT_MS &&
            attempt < MAX_ATTEMPTS) {
            attempt++;
            try {
                if (await this.checkTableForProcess(processName)) {
                    return;
                }
                throw new Error(`Instance "${processName}" not found in table (attempt ${attempt}).`);
            }
            catch (err) {
                lastError = err instanceof Error ? err.message : err;
                console.log(`clickProcessInstanceLink attempt ${attempt}: ${String(lastError)}`);
                await (0, sleep_1.sleep)(constants_1._1_SECOND_IN_MS * 3);
                await this.page
                    .reload({ timeout: 30000 })
                    .catch(() => console.log('Page reload timed out, continuing...'));
                await this.page
                    .waitForLoadState('networkidle', { timeout: 30000 })
                    .catch(() => console.log('waitForLoadState networkidle timed out, continuing...'));
                // After reload, the page may redirect away from Operate
                if (!this.page.url().includes('/operate')) {
                    await this.page
                        .goto(operateUrl, { timeout: 30000 })
                        .catch(() => console.log('Navigation to Operate timed out, continuing...'));
                    await this.page
                        .waitForLoadState('networkidle', { timeout: 30000 })
                        .catch(() => console.log('waitForLoadState after Operate navigation timed out, continuing...'));
                }
                // Operate may land on the Dashboard after reload even when the captured
                // URL pointed at the Processes view.  The filter checkboxes only exist on
                // the Processes tab, so navigate there explicitly before applying filters.
                try {
                    await this.processesTabLink.waitFor({
                        state: 'visible',
                        timeout: constants_1._1_SECOND_IN_MS * 10,
                    });
                    await this.processesTabLink.click({ timeout: constants_1._1_SECOND_IN_MS * 10 });
                    await this.page
                        .waitForLoadState('networkidle', { timeout: 30000 })
                        .catch(() => { });
                }
                catch (navErr) {
                    console.log(`Processes tab click failed after reload: ${String(navErr)}`);
                }
                // Re-apply checkbox filter lost after reload
                try {
                    await this.applyProcessStateFilter(type);
                }
                catch (toggleErr) {
                    console.log(`Checkbox toggle failed after reload: ${String(toggleErr)}`);
                }
                // Re-fill Process Instance Key filter if it was previously applied
                // but its value was cleared by the reload.
                try {
                    const isFilterVisible = await this.processInstanceKeyTextBox.isVisible();
                    if (isFilterVisible) {
                        const currentValue = await this.processInstanceKeyTextBox.inputValue();
                        if (!currentValue) {
                            await this.processInstanceKeyTextBox.fill(processName);
                        }
                    }
                }
                catch {
                    // Filter input not available, skip
                }
                await (0, sleep_1.sleep)(2000);
            }
        }
        throw new Error(`Failed to open instance "${processName}" after ${attempt} attempts (${Math.round((Date.now() - startTime) / 1000)}s elapsed). Last error: ${String(lastError)}`);
    }
    async clickProcessInstanceLinkWithPartialNameMatch(processName) {
        let retryCount = 0;
        const maxRetries = 5;
        while (retryCount < maxRetries) {
            try {
                const process = this.page
                    .locator(`td:right-of(:has-text("${processName}"))`)
                    .first();
                await (0, test_1.expect)(process).toBeVisible({ timeout: 60000 });
                await process.click({ timeout: 60000 });
                await (0, test_1.expect)(this.page.getByText('Instance History').first()).toBeVisible({
                    timeout: 30000,
                });
                return;
            }
            catch (error) {
                retryCount++;
                console.log(`Attempt ${retryCount} failed. Retrying...`);
                await this.page.reload({ waitUntil: 'domcontentloaded' });
                await this.page.waitForTimeout(10000);
            }
        }
        throw new Error(`Failed to click on process instance link containing "${processName}" after ${maxRetries} attempts.`);
    }
    getMoreFilterValueLocator(filter) {
        switch (filter.trim()) {
            case 'Process Instance Key(s)':
                return this.processInstanceKeyTextBox;
            default:
                throw new Error(`Unsupported filter: "${filter}". Add a mapping in getMoreFilterValueLocator().`);
        }
    }
    async applyMoreFilters(filter, value) {
        await this.moreFiltersButton.click();
        await this.page.getByRole('menuitem', { name: filter }).click();
        const valueInput = this.getMoreFilterValueLocator(filter);
        await (0, test_1.expect)(valueInput).toBeVisible({ timeout: 10000 });
        await valueInput.fill(value);
        await (0, sleep_1.sleep)(2000);
    }
}
exports.OperateProcessesPage = OperateProcessesPage;
