"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModelerCreatePage = void 0;
const test_1 = require("@playwright/test");
const ConnectorMarketplacePage_1 = require("./ConnectorMarketplacePage");
const LoginPage_1 = require("./LoginPage");
const sleep_1 = require("../../utils/sleep");
class ModelerCreatePage {
    page;
    generalPanel;
    taskDefinitionPanel;
    processIdInput;
    elemendIdInput;
    startEventElement;
    appendTaskButton;
    changeTypeButton;
    userTaskOption;
    serviceTaskOption;
    appendEndEventButton;
    deployAndRunMainButton;
    deployAndRunSubButton;
    startInstanceMainButton;
    startInstanceSubButton;
    viewProcessInstanceLink;
    nameInput;
    jobTypeInput;
    diagramBreadcrumb;
    editDiagramNameButton;
    diagramNameInput;
    variableInput;
    embedFormButton;
    embedButton;
    newForm;
    deployMainButton;
    deploySubButton;
    cancelButton;
    restConnectorOption;
    marketPlaceButton;
    clientIdTextbox;
    clientSecretTextbox;
    rememberCredentialsCheckbox;
    webhookMessageStartEventConnectorOption;
    webhookIdInput;
    implementationSection;
    implementationOptions;
    assignmentSection;
    priorityInput;
    secondElement;
    firstElement;
    thirdElement;
    appendElementButton;
    firstPlacedGateway;
    secondPlacedGateway;
    secondPlacedElement;
    appendPreButton;
    appendGatewayButton;
    parallelGatewayOption;
    connectToOtherElementButton;
    canvas;
    intermediateBoundaryEvent;
    intermediateWebhookConnectorOption;
    correlationKeyProcessInput;
    correlationKeyPayloadInput;
    playTab;
    continueToPlayButton;
    implementTab;
    candidateUsersInput;
    assigneeInput;
    candidateGroupsInput;
    dialog;
    tenantIdInput;
    timerEventOption;
    timerEventSettings;
    timerType;
    timerValue;
    eighthPlacedElement;
    processIdSecondLocator;
    bpmnReplaceMenu;
    constructor(page) {
        this.page = page;
        this.generalPanel = page.locator('[data-group-id="group-general"]');
        this.taskDefinitionPanel = page.getByTitle('Task definition').first();
        this.processIdInput = page.getByLabel('ID', { exact: true });
        this.elemendIdInput = page.getByLabel('ID', { exact: true });
        this.startEventElement = page.locator('.djs-hit').first();
        this.appendPreButton = page.locator('.djs-create-pad-icon > svg').first();
        this.appendTaskButton = page.getByTitle('Append task');
        this.changeTypeButton = page.getByRole('button', {
            name: 'Change element',
            exact: true,
        });
        this.userTaskOption = page
            .getByRole('listitem', { name: 'User task' })
            .locator('span')
            .first();
        this.serviceTaskOption = page.getByRole('listitem', { name: 'Service Task' });
        this.appendEndEventButton = page.getByTitle('Append end event');
        this.appendGatewayButton = page.getByTitle('append gateway');
        this.parallelGatewayOption = page.getByText('parallel gateway');
        this.dialog = page.getByRole('dialog');
        this.deployAndRunMainButton = page.getByRole('button', {
            name: 'Deploy & run',
            exact: true,
        });
        this.startInstanceMainButton = page.getByRole('button', {
            name: 'Run',
            exact: true,
        });
        this.startInstanceSubButton = this.dialog.getByRole('button', {
            name: 'Start instance',
        });
        this.deployAndRunSubButton = this.dialog.getByRole('button', {
            name: 'Deploy & run',
            exact: true,
        });
        this.viewProcessInstanceLink = page.getByRole('link', {
            name: 'View process instance',
        });
        this.nameInput = page.getByLabel('Name', { exact: true });
        this.jobTypeInput = page.getByRole('textbox', { name: /job type/i });
        this.diagramBreadcrumb = page.locator('[data-test="breadcrumb-diagram"]');
        this.editDiagramNameButton = page.getByText('Edit name');
        this.diagramNameInput = page.locator('[data-test="editable-input"]');
        this.variableInput = page.getByLabel('Variables');
        this.embedFormButton = page.getByRole('button', { name: 'Link form' });
        this.embedButton = page.locator('[data-test="confirm-move"]');
        this.newForm = page.locator('[data-test="item-New form"]');
        this.deployMainButton = page.locator('[data-test="deploy-button"]');
        this.continueToPlayButton = page.getByRole('button', { name: 'Continue' });
        this.deploySubButton = page
            .getByRole('dialog')
            .getByRole('button', { name: 'Deploy' });
        this.cancelButton = page.getByRole('button', { name: 'Cancel' });
        this.restConnectorOption = page.getByRole('listitem', {
            name: 'REST Outbound Connector',
        });
        this.marketPlaceButton = page.getByTitle('Browse Marketplace for more Connectors');
        this.clientIdTextbox = page.getByLabel('Client ID');
        this.clientSecretTextbox = page.getByLabel('Client secret');
        this.rememberCredentialsCheckbox = page.getByText('Remember credentials');
        this.webhookMessageStartEventConnectorOption = page.getByRole('listitem', {
            name: 'Webhook Message Start Event Connector',
            exact: true,
        });
        this.webhookIdInput = page.getByLabel('Webhook ID');
        this.firstElement = page.locator('[class="djs-element djs-shape"]').nth(0);
        this.secondElement = page.locator('[class="djs-element djs-shape"]').nth(1);
        this.thirdElement = page.locator('[class="djs-element djs-shape"]').nth(2);
        this.implementationSection = page.locator('[data-group-id="group-userTaskImplementation"]');
        this.implementationOptions = page.locator('#bio-properties-panel-userTaskImplementation');
        this.assignmentSection = page.locator('[data-group-id="group-assignmentDefinition"]');
        this.priorityInput = page.getByRole('textbox', { name: 'priority' });
        this.appendElementButton = page
            .locator('[class="djs-context-pad open"]')
            .first();
        this.firstPlacedGateway = page
            .locator('[data-element-id*="Gateway"]')
            .first();
        this.secondPlacedGateway = page
            .locator('[data-element-id*="Gateway"]')
            .last();
        this.secondPlacedElement = page
            .locator('[class= "djs-element djs-shape"]')
            .last();
        this.connectToOtherElementButton = page
            .getByLabel('Connect to other element')
            .locator('path');
        this.canvas = page.locator('rect').nth(1);
        this.intermediateBoundaryEvent = page.getByTitle('Append intermediate/boundary');
        this.intermediateWebhookConnectorOption = page.getByRole('listitem', {
            name: 'Webhook Intermediate Event',
        });
        this.correlationKeyPayloadInput = page.getByLabel('Correlation key (payload)');
        this.correlationKeyProcessInput = page.getByLabel('Correlation key (process)');
        this.playTab = page.getByRole('tab', {
            name: 'Play',
        });
        this.candidateUsersInput = page.getByRole('textbox', {
            name: 'candidate users',
        });
        this.assigneeInput = page.getByRole('textbox', { name: 'assignee' });
        this.candidateGroupsInput = page.getByRole('textbox', {
            name: 'candidate groups',
        });
        this.tenantIdInput = page.getByLabel('Tenant ID (Optional)');
        this.timerEventOption = page.getByRole('listitem', {
            name: 'Timer intermediate catch event',
            exact: true,
        });
        this.timerEventSettings = page.getByText(/^Timer$/).first();
        this.timerType = page.getByLabel('Type');
        this.timerValue = page.getByLabel('Value');
        this.eighthPlacedElement = page
            .locator('g:nth-child(8) > .djs-element > .djs-hit')
            .first();
        this.processIdSecondLocator = page.getByLabel('Process ID');
        this.implementTab = page.getByRole('tab', { name: 'Implement' });
        this.bpmnReplaceMenu = page.getByTestId('bpmn-replace');
    }
    async deployProcessInstance() {
        await this.clickDeployMainButton();
        await this.clickDeploySubButton();
        await (0, test_1.expect)(this.page.getByText('Diagram Deployed!')).toBeVisible({
            timeout: 180000,
        });
    }
    // Function to model a simple Camunda User Task Diagram with or without a form
    async modelCamundaUserTaskDiagram(processName, processId = '', formName = '') {
        await (0, test_1.expect)(this.generalPanel).toBeVisible({
            timeout: 180000,
        });
        await this.enterDiagramName(processName);
        if (processId.length > 0) {
            await (0, sleep_1.sleep)(1000); // When we go too fast there, modeler will missing the input
            await this.clickCanvas();
            await this.clickGeneralPropertiesPanel();
            await this.clickIdInput();
            await this.fillIdInput(processId);
            await (0, sleep_1.sleep)(1000); // When we go too fast there, modeler will missing the input
            await this.clickStartEventElement();
            try {
                await (0, test_1.expect)(this.appendElementButton).toBeVisible({ timeout: 1000 });
            }
            catch {
                await this.clickStartEventElement();
            }
        }
        await this.clickAppendElementButton();
        await this.clickAppendTaskButton();
        await this.clickChangeTypeButton();
        await this.clickUserTaskOption();
        await this.assertImplementationOption('zeebeUserTask');
        if (formName.length > 0) {
            await this.clickEmbedFormButton();
            await this.clickForm(formName);
            await this.clickEmbedButton();
        }
        await this.clickAppendElementButton();
        await this.clickAppendEndEventButton();
        await this.clickCanvas();
        await this.assertThreeElementsVisible();
    }
    async modelJobWorkerDiagram(processName) {
        await (0, test_1.expect)(this.generalPanel).toBeVisible({
            timeout: 120000,
        });
        await this.enterDiagramName(processName);
        await (0, sleep_1.sleep)(1000);
        await this.clickStartEventElement();
        await this.clickGeneralPropertiesPanel();
        await this.clickIdInput();
        await this.fillIdInput(processName);
        await this.clickStartEventElement();
        await this.clickAppendElementButton();
        await this.clickAppendTaskButton();
        await this.clickChangeTypeButton();
        await this.clickUserTaskOption();
        await this.chooseImplementationOption('jobWorker');
        await this.clickAppendElementButton();
        await this.clickAppendEndEventButton();
        await this.clickCanvas();
        await this.assertThreeElementsVisible();
    }
    async assertThreeElementsVisible() {
        await (0, test_1.expect)(this.firstElement).toBeVisible({ timeout: 30000 });
        await (0, test_1.expect)(this.secondElement).toBeVisible({ timeout: 30000 });
        await (0, test_1.expect)(this.thirdElement).toBeVisible({ timeout: 30000 });
    }
    async clickForm(name) {
        await this.page
            .locator(`[data-test="item-${name}"]`)
            .getByText(name)
            .click({ timeout: 90000 });
    }
    async runProcessInstance(variables = '') {
        await (0, sleep_1.sleep)(2000); // the canvas autosaves. This can take a second to save.
        await this.clickStartInstanceMainButton();
        await (0, test_1.expect)(this.dialog).toBeVisible({
            timeout: 30000,
        });
        if (variables.length > 0) {
            await (0, test_1.expect)(this.variableInput).toBeVisible({
                timeout: 60000,
            });
            await this.clickVariableInput();
            await this.fillVariableInput(variables);
        }
        await this.clickStartInstanceSubButton();
        await this.instanceStartedAssertion();
    }
    async switchToPlay() {
        await this.playTab.click();
    }
    async clickGeneralPropertiesPanel() {
        const isExpanded = (await this.generalPanel
            .locator('.bio-properties-panel-group-header open')
            .count()) > 0;
        if (!isExpanded) {
            await this.generalPanel.click({ timeout: 60000 });
        }
    }
    async clickIdInput() {
        try {
            await this.processIdInput.click();
        }
        catch {
            await this.processIdSecondLocator.click();
        }
    }
    async clickTaskDefinitionPropertiesPanel() {
        await this.taskDefinitionPanel.click();
    }
    async clickProcessIdInput() {
        await this.processIdInput.click();
    }
    async fillIdInput(id) {
        try {
            await this.processIdInput.fill(id);
        }
        catch {
            await this.processIdSecondLocator.fill(id);
        }
    }
    async clickElemendIdInput() {
        await this.elemendIdInput.waitFor({ state: 'visible', timeout: 10000 });
        await this.elemendIdInput.click();
    }
    async fillElementIdInput(id) {
        await (0, test_1.expect)(this.elemendIdInput).toBeVisible();
        await this.elemendIdInput.fill(id);
        await (0, test_1.expect)(this.elemendIdInput).toHaveValue(id);
        await (0, sleep_1.sleep)(1000);
    }
    async clickStartEventElement() {
        await this.startEventElement.click();
    }
    async selectStartEventElement() {
        await this.startEventElement.click();
    }
    async clickAppendTaskButton() {
        await this.hoverOnLocator(this.appendPreButton);
        await this.appendTaskButton.click({ timeout: 90000 });
    }
    async clickAppendGatewayButton() {
        await this.appendGatewayButton.click({ timeout: 90000 });
    }
    async clickChangeTypeButton() {
        try {
            await this.changeTypeButton.click({ timeout: 180000, force: true });
        }
        catch {
            await this.page.reload();
            if (await this.secondElement.isVisible({ timeout: 6000 })) {
                await this.secondElement.click({ timeout: 90000, force: true });
                await this.changeTypeButton.click({ timeout: 90000, force: true });
            }
            else {
                await this.firstElement.click({ timeout: 90000, force: true });
                await this.changeTypeButton.click({ timeout: 90000, force: true });
            }
        }
    }
    async clickUserTaskOption() {
        const maxRetries = 3;
        for (let retries = 0; retries < maxRetries; retries++) {
            try {
                if (retries === 0) {
                    await this.userTaskOption.click({ timeout: 30000, force: true });
                }
                else {
                    await this.changeTypeButton.click({ force: true, timeout: 30000 });
                    await this.userTaskOption.click({ timeout: 30000, force: true });
                }
                return;
            }
            catch (error) {
                console.error(`Click attempt ${retries + 1} failed: ${error}`);
                await new Promise((resolve) => setTimeout(resolve, 10000));
            }
        }
        throw new Error(`Failed to click the button after ${maxRetries} attempts.`);
    }
    async clickServiceTaskOption() {
        const maxRetries = 3;
        for (let retries = 0; retries < maxRetries; retries++) {
            try {
                if (retries === 0) {
                    await this.serviceTaskOption.click({ timeout: 30000, force: true });
                }
                else {
                    await this.changeTypeButton.click({ force: true, timeout: 30000 });
                    await this.serviceTaskOption.click({ timeout: 30000, force: true });
                }
                return;
            }
            catch (error) {
                console.error(`Click attempt ${retries + 1} failed: ${error}`);
                await new Promise((resolve) => setTimeout(resolve, 10000));
            }
        }
        throw new Error(`Failed to click the button after ${maxRetries} attempts.`);
    }
    async hoverOnLocator(locator, selector = '.djs-create-pad-entry') {
        const canvasState = await Promise.race([
            this.page
                .waitForSelector(selector, { state: 'visible' })
                .then(() => 'pad')
                .catch(() => {
                throw new Error('Canvas not visible');
            }),
            locator
                .waitFor({ state: 'visible' })
                .then(() => 'hover')
                .catch(() => {
                throw new Error('Locator not visible');
            }),
        ]);
        if (canvasState === 'hover') {
            await locator.hover({ timeout: 5000 });
            await this.page.waitForSelector(selector, { state: 'visible' });
        }
    }
    async clickAppendEndEventButton(parentElement) {
        try {
            await this.appendEndEventButton.click({ timeout: 5000 });
        }
        catch (error) {
            await this.page.reload();
            const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
            await sleep(10000);
            if (parentElement == undefined) {
                await this.clickSecondPlacedElement();
            }
            else if (parentElement == 'parallelGateway') {
                await this.clickSecondPlacedGateway();
            }
            await this.hoverOnLocator(this.appendElementButton);
            await this.appendEndEventButton.click({ timeout: 4000 });
        }
    }
    async clickFirstPlacedElement() {
        await this.firstElement.click({ timeout: 90000 });
    }
    async clickSecondPlacedElement() {
        await this.secondPlacedElement.click({ timeout: 60000 });
    }
    async clickFirstPlacedGateway() {
        try {
            await this.firstPlacedGateway.click({ timeout: 3000 });
            await this.appendElementButton.isVisible({ timeout: 3000 });
        }
        catch (error) {
            await this.page.reload();
            await this.firstPlacedGateway.click({ timeout: 3000 });
        }
    }
    async clickSecondPlacedGateway() {
        try {
            await this.secondPlacedGateway.click({ timeout: 3000 });
            await this.appendElementButton.isVisible({ timeout: 3000 });
        }
        catch (error) {
            await this.page.reload();
            await this.secondPlacedGateway.click({ timeout: 3000 });
        }
    }
    /**
     * Detects if the page has been redirected to the Keycloak login page
     * (session expiry) or is in the middle of an OIDC redirect, and performs
     * a re-login if necessary.
     */
    async handleSessionExpiry() {
        const currentUrl = this.page.url();
        // If we're on a login-callback or auth redirect URL, wait for navigation
        // to settle — the OIDC flow may redirect to Keycloak login form.
        if (currentUrl.includes('login-callback') ||
            currentUrl.includes('/auth/realms/')) {
            console.warn(`clickStartInstanceMainButton: detected auth redirect URL (${currentUrl}), waiting for navigation...`);
            await this.page
                .waitForLoadState('domcontentloaded', { timeout: 10000 })
                .catch(() => { });
        }
        const loginPage = new LoginPage_1.LoginPage(this.page);
        const keycloakBanner = this.page.locator('body#keycloak-bg[data-page-id="login-login"]');
        const usernameField = this.page.locator('#username');
        // Check if we landed on a login page (Keycloak form)
        const isOnLoginPage = await keycloakBanner
            .or(usernameField)
            .isVisible({ timeout: 5000 })
            .catch(() => false);
        if (!isOnLoginPage) {
            return;
        }
        console.warn('clickStartInstanceMainButton: session expired — performing re-login');
        const username = process.env.DISTRO_QA_E2E_TESTS_IDENTITY_FIRSTUSER_USERNAME || 'demo';
        const password = process.env.DISTRO_QA_E2E_TESTS_IDENTITY_FIRSTUSER_PASSWORD || '';
        await loginPage.login(username, password);
        // Wait for modeler to load after re-login
        await this.page.waitForLoadState('domcontentloaded', { timeout: 30000 });
    }
    async clickStartInstanceMainButton() {
        const maxRetries = 3;
        for (let attempt = 1; attempt <= maxRetries; attempt++) {
            try {
                if (attempt > 1) {
                    await this.page
                        .reload({ waitUntil: 'domcontentloaded' })
                        .catch((reloadErr) => {
                        console.warn(`clickStartInstanceMainButton: page.reload error (ignored): ${reloadErr}`);
                    });
                    // Handle Keycloak session expiry after reload
                    await this.handleSessionExpiry();
                }
                else {
                    // Even on first attempt, check if session already expired
                    await this.handleSessionExpiry();
                }
                if (this.page.isClosed()) {
                    throw new Error('Target page, context or browser has been closed');
                }
                // web-modeler 8.7-SNAPSHOT replaced the combined "Deploy & run" button
                // with separate "Deploy" and "Run" buttons. "Run" (startInstanceMainButton)
                // deploys and starts the instance in one click, matching the old combined behaviour.
                await this.startInstanceMainButton.waitFor({
                    state: 'visible',
                    timeout: 30000,
                });
                await this.startInstanceMainButton.click({ timeout: 30000 });
                return;
            }
            catch (error) {
                const errorMsg = String(error);
                if (errorMsg.includes('Target page, context or browser has been closed') ||
                    errorMsg.includes('page has been closed') ||
                    errorMsg.includes('Target closed')) {
                    throw error;
                }
                if (attempt === maxRetries) {
                    throw new Error(`Failed to click start process after ${maxRetries} attempts: ${error}`);
                }
                console.warn(`clickStartInstanceMainButton attempt ${attempt} failed: ${error}`);
            }
        }
    }
    async clickStartInstanceSubButton() {
        if (await this.startInstanceSubButton.isVisible({ timeout: 30000 })) {
            await this.startInstanceSubButton.click({ timeout: 30000 });
        }
        else {
            await this.deployAndRunSubButton.click({ timeout: 30000 }); //will be available from alpha7
        }
        await (0, sleep_1.sleep)(5000); // need to wait for the instance to start before leaving the page
    }
    async clickViewProcessInstanceLink() {
        await this.viewProcessInstanceLink.click({ timeout: 90000 });
    }
    async clickNameInput() {
        await this.nameInput.click();
    }
    async fillNameInput(name) {
        await this.nameInput.fill(name);
    }
    async clickJobTypeInput() {
        await this.jobTypeInput.click();
    }
    async fillJobTypeInput(name) {
        await this.jobTypeInput.fill(name);
    }
    async clickDiagramBreadcrumb() {
        await this.diagramBreadcrumb.click({ timeout: 60000 });
    }
    async clickEditDiagramNameButton() {
        await this.editDiagramNameButton.click();
    }
    async enterDiagramName(name) {
        await this.diagramNameInput.fill(name, { timeout: 60000 });
        await this.diagramNameInput.press('Enter', { timeout: 60000 });
        await (0, sleep_1.sleep)(1000);
    }
    async clickVariableInput() {
        await this.variableInput.click();
    }
    async fillVariableInput(variable) {
        await this.variableInput.fill(variable);
    }
    async clickEmbedFormButton() {
        await this.embedFormButton.click({ timeout: 90000 });
    }
    async clickEmbedButton() {
        await this.embedButton.click();
    }
    async clickDeployMainButton() {
        await this.deployMainButton.click({ timeout: 90000 });
    }
    async clickDeploySubButton() {
        await this.deploySubButton.click({ timeout: 90000 });
    }
    async clickCancelButton() {
        await this.cancelButton.click();
    }
    async clickRestConnectorOption() {
        const maxRetries = 4;
        for (let retries = 0; retries < maxRetries; retries++) {
            try {
                if (retries === 0) {
                    // First attempt
                    await this.restConnectorOption.highlight();
                    await this.restConnectorOption.click({ timeout: 60000 });
                }
                else if (retries === 1 || retries === 2) {
                    // Second or third attempt
                    await this.page.reload();
                    await this.secondElement.click({ timeout: 60000 });
                    await this.changeTypeButton.click({ force: true, timeout: 60000 });
                    await this.restConnectorOption.click({ timeout: 90000 });
                }
                else {
                    // Forth and subsequent attempts
                    await this.clickMarketPlaceButton();
                    const connectorMarketplacePage = new ConnectorMarketplacePage_1.ConnectorMarketplacePage(this.page);
                    await connectorMarketplacePage.clickSearchForConnectorTextbox();
                    await (0, sleep_1.sleep)(5000);
                    await connectorMarketplacePage.fillSearchForConnectorTextbox('REST Connector');
                    await connectorMarketplacePage.downloadConnectorToProject();
                    await this.restConnectorOption.click({ timeout: 120000 });
                }
                return;
            }
            catch (error) {
                console.error(`Click attempt ${retries + 1} failed: ${error}`);
                await new Promise((resolve) => setTimeout(resolve, 10000));
            }
        }
        throw new Error(`Failed to click the button after ${maxRetries} attempts.`);
    }
    async clickMarketPlaceButton() {
        const maxRetries = 3;
        for (let retries = 0; retries < maxRetries; retries++) {
            try {
                if (retries === 0) {
                    await this.marketPlaceButton.click({ timeout: 30000 });
                }
                else {
                    await this.changeTypeButton.click({ force: true, timeout: 30000 });
                    await this.marketPlaceButton.click({ timeout: 30000 });
                }
                return;
            }
            catch (error) {
                console.error(`Click attempt ${retries + 1} failed: ${error}`);
                await new Promise((resolve) => setTimeout(resolve, 10000));
            }
        }
        throw new Error(`Failed to click the button after ${maxRetries} attempts.`);
    }
    async completeDeploymentEndpointConfiguration() {
        await (0, test_1.expect)(this.clientIdTextbox).toBeVisible({ timeout: 60000 });
        await this.clientIdTextbox.click({ timeout: 30000 });
        await this.clientIdTextbox.fill('test', { timeout: 30000 });
        await this.clientSecretTextbox.click({ timeout: 30000 });
        await this.clientSecretTextbox.fill(process.env.DISTRO_QA_E2E_TESTS_KEYCLOAK_CLIENTS_SECRET);
        await this.rememberCredentialsCheckbox.click({ timeout: 30000 });
    }
    async completePlayConfiguration() {
        const timeout = 30000;
        let attempts = 0;
        const maxRetries = 3;
        while (attempts < maxRetries) {
            try {
                if (attempts > 0)
                    await this.switchToPlay(); // Call switchToPlay on subsequent attempts
                await this.continueToPlayButton.click({ timeout });
                // Play environment provisioning involves Zeebe deploy + cluster
                // bootstrap; on slower clusters this can take several minutes.
                // On a second visit the env is already provisioned — Play loads
                // directly without the toast, so accept either condition.
                await (0, test_1.expect)(this.page
                    .getByText('Play environment is ready')
                    .or(this.page.getByTestId('undefined-Start instance'))).toBeVisible({ timeout: 180000 });
                return; // Exit if successful
            }
            catch (error) {
                if (attempts >= maxRetries - 1)
                    throw error;
                await this.page.reload();
                attempts++;
            }
        }
    }
    async clickContinueToPlay() {
        await this.continueToPlayButton.click({ timeout: 30000 });
    }
    async clickWebhookStartEventConnectorOption() {
        const maxRetries = 3;
        for (let retries = 0; retries < maxRetries; retries++) {
            try {
                if (retries === 0) {
                    await this.webhookMessageStartEventConnectorOption.click({
                        timeout: 30000,
                    });
                }
                else {
                    await this.page.reload();
                    await this.changeTypeButton.click({ force: true, timeout: 30000 });
                    await this.webhookMessageStartEventConnectorOption.click({
                        timeout: 90000,
                    });
                }
                return;
            }
            catch (error) {
                console.error(`Click attempt ${retries + 1} failed: ${error}`);
                await new Promise((resolve) => setTimeout(resolve, 10000));
            }
        }
        throw new Error(`Failed to click the button after ${maxRetries} attempts.`);
    }
    async clickWebhookIdInput() {
        await this.webhookIdInput.click();
    }
    async clearWebhookIdInput() {
        await this.webhookIdInput.clear();
    }
    async fillWebhookIdInput(webhookId) {
        await this.webhookIdInput.fill(webhookId);
    }
    async hoverOnStartEvent() {
        await this.hoverOnLocator(this.startEventElement, '.djs-context-pad');
    }
    async switchToImplementTab() {
        await this.implementTab.click({ timeout: 30000 });
    }
    async clickStartEvent() {
        await this.startEventElement.click({ timeout: 30000 });
    }
    async assertScenarioNameVisible(scenarioName) {
        await (0, test_1.expect)(this.page.getByTestId('instance-header').getByText(scenarioName)).toBeVisible();
    }
    async instanceStartedAssertion() {
        const success = this.page.getByText('Instance started!');
        const failure = this.page.getByText('Instance could not be started');
        // Race success against the error banner so we don't burn 180 s waiting
        // for a toast that will never appear when Zeebe rejects the start request.
        for (let attempt = 1; attempt <= 2; attempt++) {
            await (0, test_1.expect)(success.or(failure)).toBeVisible({ timeout: 60000 });
            if (await success.isVisible())
                return;
            if (attempt === 2) {
                throw new Error('Process instance could not be started after 2 attempts');
            }
            await this.clickStartInstanceMainButton();
            await this.completeDeploymentEndpointConfiguration();
            await this.clickStartInstanceSubButton();
        }
    }
    async assertImplementationOption(implementationType) {
        await this.expandImplementationOptionIfNecessary();
        (0, test_1.expect)(await this.implementationOptions.inputValue()).toEqual(implementationType);
    }
    async chooseImplementationOption(implementationType) {
        await this.implementationSection.click();
        if ((await this.implementationOptions.inputValue()) == implementationType) {
            console.log(`${implementationType} is already selected.`);
        }
        else {
            await this.implementationOptions.selectOption(implementationType);
        }
        await this.assertImplementationOption(implementationType);
    }
    async expandImplementationOptionIfNecessary() {
        const isExpanded = (await this.implementationSection
            .locator('.bio-properties-panel-group-header empty open')
            .count()) > 0;
        if (!isExpanded) {
            await this.implementationSection.click();
        }
    }
    async expandAssignmentSection() {
        const isExpanded = (await this.assignmentSection
            .locator('[data-group-id="group-assignmentDefinition"] .bio-properties-panel-group-header.open')
            .count()) > 0;
        if (!isExpanded) {
            await this.assignmentSection.click({ timeout: 60000 });
        }
    }
    async clickAppendElementButton() {
        for (let attempt = 1; attempt <= 3; attempt++) {
            try {
                await this.hoverOnLocator(this.appendPreButton);
                return; // Exit loop if successful
            }
            catch (error) {
                if (attempt === 3)
                    throw error; // Rethrow after 3 failed attempts
                // Recovery: reload to re-render the canvas, then re-select the start
                // event so the context pad (append button) becomes available again.
                await this.page.reload();
                await (0, test_1.expect)(this.generalPanel).toBeVisible({ timeout: 30000 });
                await this.startEventElement.click({ timeout: 10000 }).catch(() => { });
            }
        }
    }
    async clickParallelGatewayOption() {
        await this.parallelGatewayOption.click({ timeout: 90000 });
    }
    async clickConnectToOtherElementButton() {
        await this.connectToOtherElementButton.click({ timeout: 60000 });
    }
    async clickPriorityInput() {
        try {
            await this.priorityInput.click();
        }
        catch (error) {
            await this.assignmentSection.click({ timeout: 60000 });
            await this.priorityInput.click({ timeout: 60000 });
        }
    }
    async fillPriorityInput(priority) {
        await this.priorityInput.fill(priority, { timeout: 60000 });
    }
    async clickCanvas() {
        await this.canvas.click({ timeout: 60000 });
    }
    async addParallelUserTasks(numberOfTasks, taskName) {
        try {
            await this.clickAppendElementButton();
        }
        catch (error) {
            await this.page.reload();
            const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
            await sleep(10000);
            await this.clickFirstPlacedElement();
            await this.hoverOnLocator(this.appendElementButton);
        }
        await this.clickAppendGatewayButton();
        await this.clickChangeTypeButton();
        await this.clickParallelGatewayOption();
        await this.clickAppendElementButton();
        await this.clickAppendTaskButton();
        await this.clickChangeTypeButton();
        await this.clickUserTaskOption();
        await this.clickGeneralPropertiesPanel();
        await this.clickNameInput();
        await this.fillNameInput(taskName + '1');
        await this.clickIdInput();
        await this.fillIdInput(taskName + '1');
        await this.assertImplementationOption('zeebeUserTask');
        await this.clickAppendElementButton();
        await this.clickAppendGatewayButton();
        await this.clickChangeTypeButton();
        await this.clickParallelGatewayOption();
        for (let i = 2; i <= numberOfTasks; i++) {
            await this.clickFirstPlacedGateway();
            await this.clickAppendElementButton();
            await this.clickAppendTaskButton();
            await this.clickChangeTypeButton();
            await this.clickUserTaskOption();
            await this.clickNameInput();
            await this.fillNameInput(taskName + i);
            await this.clickIdInput();
            await this.fillIdInput(taskName + i);
            await this.assertImplementationOption('zeebeUserTask');
            await this.clickConnectToOtherElementButton();
            await this.clickSecondPlacedGateway();
            await this.clickCanvas();
        }
        await this.clickSecondPlacedGateway();
    }
    async setPriority(taskName, priority, numberOfTasks) {
        for (let i = 1; i <= numberOfTasks; i++) {
            const userTaskId = taskName + i;
            const priorityUserTask = this.page.locator(`g[data-element-id="${userTaskId}"]`);
            await priorityUserTask.click();
            await this.clickPriorityInput();
            await this.fillPriorityInput(priority.toString());
            await this.clickCanvas();
            priority += 25;
        }
    }
    async clickIntermediateBoundaryEvent() {
        await this.intermediateBoundaryEvent.click({ timeout: 60000 });
    }
    async clickIntermediateWebhookConnectorOption() {
        await this.intermediateWebhookConnectorOption.click({ timeout: 60000 });
    }
    async clickCorrelationKeyProcessInput() {
        await this.correlationKeyProcessInput.click({ timeout: 60000 });
    }
    async fillCorrelationKeyProcessInput(correlationKeyProcess) {
        await this.correlationKeyProcessInput.fill(correlationKeyProcess);
    }
    async clickCorrelationKeyPayloadInput() {
        await this.correlationKeyPayloadInput.click({ timeout: 60000 });
    }
    async fillCorrelationKeyPayloadInput(correlationKeyPayload) {
        await this.correlationKeyPayloadInput.fill(correlationKeyPayload);
    }
    async selectUserTask(userTask) {
        await this.page.locator(`[data-element-id="${userTask}"]`).click();
    }
    async clickCandidateUsersInput() {
        await this.candidateUsersInput.click({ timeout: 60000 });
    }
    async fillCandidateUsersInput(candidateUser) {
        await this.candidateUsersInput.fill(candidateUser, { timeout: 60000 });
    }
    async clickCandidateGroupsInput() {
        await this.candidateGroupsInput.click({ timeout: 60000 });
    }
    async fillCandidateGroupsInput(candidateGroup) {
        await this.candidateGroupsInput.fill(candidateGroup, { timeout: 60000 });
    }
    async clickAssigneeInput() {
        await this.assigneeInput.click({ timeout: 60000 });
    }
    async fillAssigneeInput(name) {
        await this.assigneeInput.fill(name, { timeout: 60000 });
    }
    async clickTenantIdInput() {
        await this.tenantIdInput.click({ timeout: 60000 });
    }
    async fillTenantIdInput(tenant) {
        await this.tenantIdInput.fill(tenant, { timeout: 60000 });
    }
    async clickTimerEventOption() {
        await this.timerEventOption.click();
    }
    async clickTimerEventSettings() {
        await this.timerEventSettings.click();
    }
    async selectTimerType(type) {
        await this.timerType.selectOption(type);
    }
    async clickTimerValue() {
        await this.timerValue.click();
    }
    async fillTimerValue(value) {
        await this.timerValue.fill(value);
    }
    async clickEighthPlacedElement() {
        await this.eighthPlacedElement.click();
    }
    async reloadPage() {
        await this.page.reload();
    }
}
exports.ModelerCreatePage = ModelerCreatePage;
