"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlayPage = void 0;
const test_1 = require("@playwright/test");
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
const clickLocatorWithRetry_1 = require("../../utils/assertionHelpers/clickLocatorWithRetry");
const maxWaitTimeSeconds = 180000;
class PlayPage {
    page;
    completeJobButton;
    viewScenarioButton;
    runAllScenariosButton;
    confirmDeleteScenarioButton;
    viewAllScenariosButton;
    getScenarioRowByName;
    getScenarioRow;
    diagram;
    startInstanceButton;
    startInstanceWithCachedButton;
    configureTestPanel;
    configureTestPanelStartButton;
    notifications;
    scenarioSavedToast;
    scenarioDetailNameInput;
    scenarioDetailSaveButton;
    loadingInstanceDetailsText;
    retryButton;
    dialog;
    inputPanelStartButton;
    constructor(page) {
        this.page = page;
        this.dialog = page.getByRole('dialog');
        this.completeJobButton = page
            .getByTestId('diagram')
            .getByLabel('Complete job');
        this.viewScenarioButton = page.getByRole('button', { name: 'View scenario' });
        this.runAllScenariosButton = page.getByRole('button', {
            name: 'Run all scenarios',
        });
        this.confirmDeleteScenarioButton = page
            .getByRole('dialog', { name: 'Delete scenario' })
            .getByRole('button', { name: 'Delete', exact: true });
        // After saving a scenario, the Scenarios panel is in detail-view mode.
        // To get back to the list (where "Run all scenarios" lives in
        // ScenarioTopBar), click the "Back to scenarios" ghost button at the
        // top of the detail panel — see ScenarioDetail/index.tsx Header.
        // This replaces the legacy bottom-bar `(View all)` link that used to
        // close the saved-scenario view.
        this.viewAllScenariosButton = page.getByRole('button', {
            name: 'Back to scenarios',
            exact: true,
        });
        this.getScenarioRowByName = (scenarioName) => page.locator('tr', { hasText: scenarioName });
        this.getScenarioRow = (scenarioName) => page.locator('tr', { hasText: scenarioName });
        this.diagram = page.getByTestId('diagram');
        this.startInstanceButton = this.diagram.getByLabel('Start instance', {
            exact: true,
        });
        this.startInstanceWithCachedButton = page.getByLabel('Start instance with cached');
        this.configureTestPanel = page.getByTestId('configure-test-panel');
        this.configureTestPanelStartButton = this.configureTestPanel.getByRole('button', { name: /^Start( with .*)?$/, exact: false });
        this.notifications = page.locator('.cds--toast-notification');
        // Hub PR #25327 (2026-06-22) removed the standalone "Save scenario" modal
        // and moved recording into the Scenarios side panel's detail view. The
        // detail view renders a TextInput with id="scenario-name" and a primary
        // "Save scenario" button. A success toast with title "Scenario saved"
        // is emitted via @camunda/c4-notifications — see
        // ScenarioDetail/useScenarioEditor.ts.
        this.scenarioDetailNameInput = page.locator('input#scenario-name');
        this.scenarioDetailSaveButton = page.getByRole('button', {
            name: 'Save scenario',
            exact: true,
        });
        // c4-notifications wraps Carbon ToastNotification with role="alert" for
        // non-actionable toasts (see Notification.tsx in @camunda/c4-notifications).
        // Anchor on the accessible role instead of the Carbon CSS class so the
        // locator is resilient to Carbon version bumps.
        this.scenarioSavedToast = page
            .getByRole('alert')
            .filter({ hasText: 'Scenario saved' });
        this.loadingInstanceDetailsText = this.page.getByText('Loading instance details...');
        this.retryButton = this.page.getByRole('button', { name: 'Retry' });
        // New Play UI (8.10+): "Configure scenario" opens an input panel with a plain "Start" button.
        this.inputPanelStartButton = page.getByRole('button', {
            name: 'Start',
            exact: true,
        });
    }
    async waitForCompleteJobButtonToBeAvailable() {
        await (0, test_1.expect)(this.completeJobButton).toBeVisible({
            timeout: maxWaitTimeSeconds,
        });
    }
    async clickCompleteJobButton() {
        await this.completeJobButton.waitFor({ state: 'visible', timeout: 30000 });
        await this.completeJobButton.click();
    }
    async clickStartInstanceButton() {
        const scenariosRegion = this.page.getByRole('region', { name: 'Scenarios' });
        const backToScenariosButton = scenariosRegion.getByRole('button', {
            name: 'Back to scenarios',
        });
        const closeScenariosButton = scenariosRegion.getByRole('button', {
            name: 'Close',
        });
        // When "Configure scenario" is clicked with a prior scenario already saved,
        // the Play UI opens scenario DETAILS (with "Back to scenarios") instead of
        // the input panel. Close the Scenarios panel to reveal the canvas start controls.
        const isDetailsView = await backToScenariosButton
            .waitFor({ state: 'visible', timeout: 3000 })
            .then(() => true)
            .catch(() => false);
        if (isDetailsView) {
            await closeScenariosButton.click();
        }
        const startTrigger = this.configureTestPanelStartButton
            .or(this.inputPanelStartButton)
            .or(this.startInstanceButton)
            .or(this.startInstanceWithCachedButton)
            .first();
        await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, startTrigger, {
            totalTimeout: maxWaitTimeSeconds,
            visibilityTimeout: 30000,
            maxRetries: 5,
        });
    }
    async dismissStartModal() {
        const buttonVariations = [
            'Start a process instance',
            'Start another instance',
            'Start new instance',
            'Start instance',
        ];
        // Wait for the page to settle before checking for modal buttons
        await this.page.waitForLoadState('domcontentloaded');
        const maxAttempts = 3;
        for (let attempt = 0; attempt < maxAttempts; attempt++) {
            for (const buttonName of buttonVariations) {
                const button = this.page.getByRole('button', { name: buttonName });
                const count = await button.count();
                if (count > 0) {
                    await button.waitFor({ state: 'visible', timeout: 10000 });
                    await button.click();
                    return;
                }
            }
            if (attempt < maxAttempts - 1) {
                await this.page.waitForLoadState('load');
            }
        }
        // No modal present — new Play UI skips the modal entirely (Configure scenario
        // opens the input panel directly without a modal step).
    }
    async clickStartInstanceWithCachedButton() {
        await this.diagram.waitFor({ state: 'visible', timeout: 30000 });
        await this.startInstanceWithCachedButton.click({ timeout: 30000 });
    }
    async waitForInstanceDetailsToBeLoaded() {
        // Do NOT use page.reload() — it destroys Play's embedded context.
        await (0, test_1.expect)(this.page.getByText(/process instance key/i)).toBeVisible({
            timeout: maxWaitTimeSeconds,
        });
        await (0, test_1.expect)(this.page.getByText(/This process instance has no variables/i)).toBeVisible({
            timeout: maxWaitTimeSeconds,
        });
    }
    async waitForNextElementToBeActive(historyItem) {
        const locator = this.page.getByText(new RegExp(`^${historyItem}`, 'i'));
        // Do NOT use page.reload() here — Play is embedded in the modeler and
        // reloading destroys the Play instance context, making the diagram
        // permanently invisible. Use a long timeout instead, consistent with
        // waitForCompleteJobButtonToBeAvailable.
        await (0, test_1.expect)(locator.first()).toBeVisible({ timeout: maxWaitTimeSeconds });
    }
    async waitForProcessToBeCompleted() {
        // Do NOT use page.reload() — it destroys Play's embedded context.
        await (0, test_1.expect)(this.page.getByText('Completed')).toBeVisible({
            timeout: maxWaitTimeSeconds,
        });
    }
    async waitForScenarioRecordPanelReady() {
        // Hub PR #25327 (2026-06-22) removed the standalone "Save scenario" modal.
        // Starting a Play run now auto-opens the Scenarios side panel in "record"
        // mode with the scenario-name input + a primary "Save scenario" button.
        // This method waits for that record-mode panel to be ready for input.
        //
        // `state: 'hidden'` already resolves immediately when the notification is
        // absent, so no try/catch is needed — letting a real timeout surface is
        // intentional (it signals a stuck stale toast blocking subsequent input).
        await this.notifications.first().waitFor({ state: 'hidden', timeout: 60000 });
        await (0, test_1.expect)(this.scenarioDetailNameInput).toBeVisible({ timeout: 30000 });
    }
    async clickViewScenarioButton() {
        await this.viewScenarioButton.waitFor({ state: 'visible', timeout: 30000 });
        await this.viewScenarioButton.click();
    }
    async enterScenarioName(scenarioName) {
        // New flow: the name input lives directly inside the auto-opened record
        // panel — no modal to click open first. Fill and blur so the validation
        // (canSave = isDirty && !isNameEmpty && !isNameDuplicate) commits before
        // the Save scenario button is clicked.
        await this.scenarioDetailNameInput.waitFor({
            state: 'visible',
            timeout: 30000,
        });
        await this.scenarioDetailNameInput.clear();
        await this.scenarioDetailNameInput.fill(scenarioName);
        await this.scenarioDetailNameInput.press('Tab');
    }
    async updateScenarioName(newScenarioName) {
        // Mirror enterScenarioName's blur step so canSave validation commits
        // before any subsequent Save click.
        await this.scenarioDetailNameInput.fill(newScenarioName);
        await this.scenarioDetailNameInput.press('Tab');
    }
    async clickViewAllScenariosButton() {
        await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.viewAllScenariosButton);
        await this.viewAllScenariosButton.click();
    }
    async confirmSaveScenario() {
        // Click the in-panel "Save scenario" primary button. It is gated by the
        // canSave predicate in useScenarioEditor.ts — a non-empty, non-duplicate
        // name and a completed instance are both required. enterScenarioName()
        // and waitForProcessToBeCompleted() satisfy those before this is called.
        await (0, test_1.expect)(this.scenarioDetailSaveButton).toBeVisible({ timeout: 30000 });
        await (0, test_1.expect)(this.scenarioDetailSaveButton).toBeEnabled({ timeout: 30000 });
        await this.scenarioDetailSaveButton.click({ timeout: 30000 });
        // Saving fires a c4-notifications toast with title "Scenario saved".
        // Wait for it as the success signal that replaces the legacy
        // modal-hidden assertion.
        await (0, test_1.expect)(this.scenarioSavedToast).toBeVisible({ timeout: 30000 });
    }
    async assertSavedScenarioNameInPanel(scenarioName) {
        // After save, useScenarioEditor.saveTest() calls
        // scenariosStore.stopRecording() + setSelectedScenario(newScenario) and
        // processInstanceStore.reset(). The Scenarios side panel stays open in
        // 'view' mode for the just-saved scenario, rendering the name as the
        // TestName h4 (see ScenarioDetail/styled.tsx and index.tsx). The legacy
        // instance-header scenarioName slot is cleared by the reset and is no
        // longer the source of truth for the saved name.
        await (0, test_1.expect)(this.page.getByRole('heading', { name: scenarioName, exact: true })).toBeVisible({ timeout: 30000 });
    }
    async getDeleteIconForScenario(scenarioName) {
        const scenarioRow = this.page
            .locator('tr')
            .filter({ has: this.page.getByText(scenarioName, { exact: true }) });
        return scenarioRow.getByLabel('Delete scenario');
    }
    async deleteScenario(scenarioName) {
        const deleteIcon = await this.getDeleteIconForScenario(scenarioName);
        await deleteIcon.waitFor({ state: 'visible', timeout: 10000 });
        await deleteIcon.click();
    }
    async confirmDeleteScenario() {
        await this.confirmDeleteScenarioButton.waitFor({
            state: 'visible',
            timeout: 10000,
        });
        await this.confirmDeleteScenarioButton.click();
    }
    async clickRunAllScenariosButton() {
        await this.runAllScenariosButton.waitFor({
            state: 'visible',
            timeout: 30000,
        });
        await this.runAllScenariosButton.click();
    }
    async clickmessagePublishButton() {
        await this.diagram.waitFor({ state: 'visible', timeout: 30000 });
        const publishIcon = this.diagram
            .locator('div.djs-overlays')
            .getByLabel('Publish message', { exact: true });
        await publishIcon.click({ timeout: 30000 });
    }
    async assertScenarioCompleted(scenarioName) {
        await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.page
            .locator('tr', { hasText: scenarioName })
            .locator('text=Completed'), {
            totalTimeout: 120000,
            visibilityTimeout: 30000,
            maxRetries: 5,
            postAction: async () => {
                if (await this.retryButton.isVisible()) {
                    await this.retryButton.click();
                }
            },
        });
    }
}
exports.PlayPage = PlayPage;
