"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClusterPage = void 0;
const test_1 = require("@playwright/test");
const sleep_1 = require("../../utils/sleep");
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
const clickLocatorWithRetry_1 = require("../../utils/assertionHelpers/clickLocatorWithRetry");
const clusterVersions_1 = require("../../utils/clusterVersions");
class ClusterPage {
    page;
    defaultClusterType = 'G3-Dev';
    testInfo;
    createNewClusterButton;
    clusterNameInput;
    createClusterButton;
    clusterCreatingStatusText;
    clusterHealthyStatusText;
    clusterHealthyIndicatorSelector;
    clusterGenerationCompleteMessage;
    clustersBreadcrumb;
    deleteClusterButton;
    confirmDeleteInput;
    dangerDeleteButton;
    testClusterLink;
    connectorSecretsTab;
    createAClusterButton;
    clusterVersionOption;
    g3DevClusterType;
    belgiumRegion;
    londonRegion;
    finlandRegion;
    alphaTab;
    devTab;
    stableTab;
    qaGenerationsTab;
    gcpRegion;
    clustersList;
    tasklistV1Api;
    tasklistV2Api;
    cluster;
    clusterHealthiness;
    clusterLink;
    dialog;
    clusterVersion;
    constructor(page, testInfo) {
        this.page = page;
        this.testInfo = testInfo;
        this.dialog = page.getByRole('dialog');
        this.createNewClusterButton = this.createNewClusterButton = page
            .getByRole('button', {
            name: 'Create new cluster',
        })
            .or(this.page.getByRole('button', {
            name: 'Create cluster',
        }));
        this.clusterNameInput = page.getByPlaceholder('Enter a name for the cluster');
        this.createClusterButton = page.getByRole('button', {
            name: 'Create cluster',
        });
        this.clusterCreatingStatusText = page.getByText('Creating', { exact: true });
        this.clusterHealthyStatusText = page.getByText('Healthy', { exact: true });
        this.clusterHealthyIndicatorSelector = '[class="healthy healthIndicator"]';
        this.clusterGenerationCompleteMessage = page.getByText('Test Cluster is healthy and ready to use');
        this.clustersBreadcrumb = page
            .getByLabel('Breadcrumb')
            .getByText('Clusters', { exact: true });
        this.deleteClusterButton = page.getByRole('button', { name: 'Delete' });
        this.confirmDeleteInput = page.getByRole('textbox', {
            name: 'Type the word DELETE to confirm',
        });
        this.dangerDeleteButton = page.getByRole('button', { name: 'danger Delete' });
        this.testClusterLink = page.getByRole('link', { name: 'Test Cluster' });
        this.connectorSecretsTab = page.getByRole('tab', {
            name: 'Connector Secrets',
        });
        this.createAClusterButton = page.getByRole('button', {
            name: 'Create a Cluster',
        });
        this.clusterVersionOption = page.getByText(`${process.env.CLUSTER_VERSION}`, { exact: true });
        this.g3DevClusterType = page.locator('label').filter({
            hasText: this.defaultClusterType,
        });
        this.londonRegion = page.locator('label').filter({
            hasText: 'London, Europe (europe-west2)',
        });
        this.belgiumRegion = page.locator('label').filter({
            hasText: 'Chaos, Belgium, Europe (europe-west1)',
        });
        this.finlandRegion = page.locator('label').filter({
            hasText: 'Finland, Europe (europe-north1)',
        });
        this.alphaTab = page.getByRole('tab', { name: 'Alpha' });
        this.devTab = page.getByRole('tab', { name: 'Internal Dev' });
        this.stableTab = page.getByRole('tab', { name: 'Stable' });
        this.qaGenerationsTab = page.getByRole('tab', { name: 'QA Generations' });
        this.gcpRegion = page.getByRole('tab', {
            name: 'GCP',
        });
        this.clustersList = page
            .getByRole('row')
            .filter({ hasNotText: 'Generation' }); //Filter out header row
        this.tasklistV1Api = page.getByText('Tasklist API v1 (legacy)');
        this.tasklistV2Api = page.getByText('Tasklist API v2');
        this.cluster = (clusterName) => this.clustersList.filter({ hasText: clusterName }).first();
        this.clusterHealthiness = (clusterName) => this.cluster(clusterName).getByText(`Healthy`, {
            exact: true,
        });
        this.clusterLink = (clusterName) => this.cluster(clusterName).getByRole('link', {
            name: clusterName,
        });
        this.clusterVersion = (clusterName, versionText) => this.cluster(clusterName).getByText(versionText);
    }
    async clickClusterBanner() {
        await this.page
            .getByRole('banner')
            .getByRole('link', { name: 'Clusters' })
            .click({ timeout: 60000 });
    }
    async deleteCluster(name) {
        await this.page.waitForTimeout(1000);
        const clusterInstance = this.cluster(name).first();
        if ((await clusterInstance.count()) <= 0) {
            console.log(`No clusters found with name ${name}, skipping deletion.`);
            return;
        }
        await clusterInstance.waitFor({ timeout: 10000 });
        let deleteButtons = this.cluster(name).getByRole('button', {
            name: 'Delete',
        });
        while ((await deleteButtons.count()) > 0) {
            const deleteButton = deleteButtons.nth(0);
            // Wait for the Delete button to become visible — a cluster in a transient
            // state (e.g. just created by a concurrent setup worker) may have the row
            // present in the DOM but the button not yet rendered. Without this wait
            // the while-loop would spin forever since count() stays > 0.
            try {
                await (0, test_1.expect)(deleteButton).toBeVisible({ timeout: 10000 });
            }
            catch {
                await this.page.reload({ waitUntil: 'domcontentloaded' }).catch(() => { });
                deleteButtons = this.cluster(name).getByRole('button', {
                    name: 'Delete',
                });
                continue;
            }
            try {
                await deleteButton.click({ force: true, timeout: 60000 });
            }
            catch (error) {
                await this.clickClusterBanner();
                await (0, test_1.expect)(deleteButton).toBeVisible({ timeout: 60000 });
                await deleteButton.click({ force: true, timeout: 60000 });
            }
            await (0, test_1.expect)(this.dialog).toBeVisible({ timeout: 60000 });
            await (0, test_1.expect)(this.confirmDeleteInput).toBeVisible({ timeout: 60000 });
            await this.confirmDeleteInput.click({ force: true, timeout: 60000 });
            await this.confirmDeleteInput.fill('DELETE', { timeout: 60000 });
            const dangerDeleteButtons = await this.dangerDeleteButton.all();
            const lastDangerDeleteButton = dangerDeleteButtons[dangerDeleteButtons.length - 1];
            await lastDangerDeleteButton.click();
            await (0, test_1.expect)(this.cluster(name).getByText('Deleting...', { exact: true })).not.toBeVisible({ timeout: 60000 });
            await (0, test_1.expect)(this.dialog).not.toBeVisible({ timeout: 60000 });
            // Refresh the list of delete buttons
            deleteButtons = this.cluster(name).getByRole('button', { name: 'Delete' });
        }
        await this.page.waitForTimeout(500);
    }
    async clickClusterTab() {
        await Promise.race([
            this.page.waitForURL(/\/clusters/, {
                timeout: 60000,
            }),
            this.clickClusterBanner(),
        ]);
    }
    async clickCreateNewClusterButton() {
        await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.createNewClusterButton, {
            visibilityTimeout: 20000,
            totalTimeout: 80000,
            postAction: async () => {
                await this.clickClusterBanner();
            },
        });
    }
    async clickClusterNameInput() {
        await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.clusterNameInput, {
            postAction: async () => {
                await this.clickClusterBanner();
            },
        });
    }
    async fillClusterNameInput(name) {
        await this.clusterNameInput.fill(name);
    }
    extractClusterIdFromUrl(url) {
        const clusterIdMatch = url.match(/\/cluster\/([a-f0-9-]+)/);
        return clusterIdMatch ? clusterIdMatch[1] : null;
    }
    async logClusterCreationInfo(clusterName) {
        try {
            await this.page.waitForURL(/\/cluster\/[a-f0-9-]+$/, { timeout: 60000 });
            const currentUrl = this.page.url();
            const clusterId = this.extractClusterIdFromUrl(currentUrl);
            console.log(`🎉 Cluster "${clusterName}" created successfully with ID: ${clusterId || 'Unknown'} at ${new Date().toISOString()}`);
        }
        catch (error) {
            console.warn(`⚠️ Could not extract cluster info for "${clusterName}": ${error}`);
        }
    }
    async createCluster(name, region = 'GCP', tasklistV1Api) {
        await this.clickClusterTab();
        await this.deleteCluster(name);
        // A concurrent setup worker (e.g. another version's test suite running in
        // the same org) may have created a same-named cluster in the window between
        // our deleteCluster check and now. Reload and delete again to catch it.
        await this.page.waitForTimeout(3000);
        await this.page.reload({ waitUntil: 'domcontentloaded' }).catch(() => { });
        await this.deleteCluster(name);
        await this.clickCreateNewClusterButton();
        await this.clickClusterNameInput();
        await this.fillClusterNameInput(name);
        await this.clickClusterType();
        await this.page.getByRole('tab', { name: region }).click();
        await this.selectSubRegion(region);
        await this.clickClusterOption(process.env.CLUSTER_VERSION);
        await this.determineTasklistAPI(tasklistV1Api);
        await this.clickCreateClusterButton();
        await this.logClusterCreationInfo(name);
        await this.clickClustersBreadcrumb(name);
    }
    async selectSubRegion(region) {
        if (region === 'GCP') {
            if (process.env.IS_PROD == 'true') {
                await (0, test_1.expect)(this.londonRegion).toBeVisible({ timeout: 20000 });
                await this.londonRegion.click();
            }
            else {
                const regions = [
                    { name: 'Belgium', locator: this.belgiumRegion },
                    { name: 'Finland', locator: this.finlandRegion },
                ];
                const chosen = regions[Math.floor(Math.random() * regions.length)];
                console.log(`Selected region: ${chosen.name}`);
                await (0, test_1.expect)(chosen.locator).toBeVisible({ timeout: 20000 });
                await chosen.locator.click();
            }
        }
    }
    async determineTasklistAPI(tasklistV1Api) {
        // Determine tasklistV1Api from project name if not explicitly provided
        if (tasklistV1Api === undefined) {
            const projectName = this.testInfo?.project.name || '';
            tasklistV1Api =
                projectName.includes('v1') || projectName.includes('8.8-v1');
            console.log(`Auto-detected Tasklist API version from project '${projectName}': ${tasklistV1Api ? 'V1' : 'V2'}`);
        }
        if (tasklistV1Api) {
            await this.clickTasklistV1Api();
        }
    }
    async clickClusterType() {
        if (process.env.IS_PROD !== 'true') {
            await (0, test_1.expect)(this.g3DevClusterType).toBeVisible({ timeout: 60000 });
            await this.g3DevClusterType.click();
        }
    }
    async clickCreateClusterButton() {
        await this.createClusterButton.click();
    }
    async clickClustersBreadcrumb(clusterName) {
        const clusterRow = this.cluster(clusterName);
        const clusterRowVisible = clusterRow
            .getByText('Creating', { exact: true })
            .or(clusterRow.getByText('Healthy', { exact: true }));
        try {
            await (0, test_1.expect)(this.clustersBreadcrumb).toBeVisible({ timeout: 60000 });
            await this.clustersBreadcrumb.click({ timeout: 60000 });
            await (0, test_1.expect)(clusterRow.getByText('Creating', { exact: true })).toBeVisible({ timeout: 30000 });
        }
        catch (error) {
            await this.clickClusterBanner();
            await (0, test_1.expect)(clusterRowVisible).toBeVisible({ timeout: 30000 });
        }
    }
    async clickClusterLink(name) {
        await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.clusterLink(name), {
            postAction: async () => {
                await this.clickClusterBanner();
            },
        });
    }
    async clickConnectorSecretsTab(clusterName) {
        await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.connectorSecretsTab, {
            postAction: async () => {
                await this.clickClusterBanner();
                await this.clickClusterLink(clusterName);
            },
        });
    }
    async clickLatestStableForMinorVersion() {
        const minorVersion = process.env.MINOR_VERSION;
        if (!minorVersion) {
            throw new Error('MINOR_VERSION env var is required for auto-detecting the latest stable generation');
        }
        const escapedVersion = minorVersion.replace('.', '\\.');
        const stableOption = this.page
            .getByText(new RegExp(`^Camunda ${escapedVersion}\\+`))
            .first();
        await this.clickStableTab();
        await (0, test_1.expect)(stableOption).toBeVisible({ timeout: 60000 });
        console.log(`Auto-selecting latest stable generation for Camunda ${minorVersion}`);
        await stableOption.click({ timeout: 60000 });
    }
    async clickClusterOption(version) {
        if (!version) {
            await this.clickLatestStableForMinorVersion();
            return;
        }
        const tabs = [
            this.clickDevTab,
            this.clickQAGenerationsTab,
            this.clickStableTab,
            this.clickAlphaTab,
        ];
        const maxRetries = 3;
        for (let attempt = 0; attempt < maxRetries; attempt++) {
            try {
                if (version === clusterVersions_1.ClusterVersion.EIGHT_EIGHT_SNAPSHOT) {
                    await this.clickDevTab();
                    await this.clusterVersionOption.scrollIntoViewIfNeeded();
                    await (0, test_1.expect)(this.clusterVersionOption).toBeVisible({ timeout: 60000 });
                    await this.clusterVersionOption.click({ timeout: 60000 });
                    return;
                }
                for (const clickTab of tabs) {
                    try {
                        await clickTab.call(this);
                        await this.clusterVersionOption.click({ timeout: 30000 });
                        return;
                    }
                    catch (error) {
                        console.log(`Version option ${version} not found in this tab, trying next tab if available...`);
                    }
                }
            }
            catch (error) {
                const errorMessage = error instanceof Error ? error.message : 'Unknown error';
                console.error('Error clicking tab or cluster version option: ' + errorMessage);
            }
        }
        throw new Error('Failed to find cluster generation');
    }
    async createClusterIfNotExists(clusterName, region = 'GCP') {
        await (0, sleep_1.sleep)(15000);
        if ((await this.cluster(clusterName).isVisible({ timeout: 20000 })) &&
            (await this.clusterHealthiness(clusterName).isVisible({ timeout: 20000 }))) {
            console.log(`${clusterName} exists and is healthy.`);
        }
        else {
            await this.createCluster(clusterName, region);
            await this.assertClusterHealthyStatusWithRetry(clusterName, 120000, 600000);
        }
    }
    async assertClusterHealthyStatusWithRetry(name, visibilityTimeout = 100000, totalTimeout = 420000, isUpgradeScenario = false) {
        // For upgrade scenarios, use much longer timeouts and more retries instead of fixed waits
        const actualTotalTimeout = isUpgradeScenario ? 900000 : totalTimeout; // 15 minutes for upgrades
        const actualVisibilityTimeout = isUpgradeScenario
            ? 15000
            : visibilityTimeout; // Shorter individual checks
        const maxRetries = isUpgradeScenario
            ? Math.ceil(actualTotalTimeout / actualVisibilityTimeout) + 5
            : 5;
        console.log(isUpgradeScenario
            ? `Checking cluster health post-upgrade with extended timeouts (${actualTotalTimeout / 60000} min total, ${maxRetries} retries)`
            : `Checking cluster health: ${name}`);
        await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.clusterHealthiness(name), {
            visibilityTimeout: actualVisibilityTimeout,
            totalTimeout: actualTotalTimeout,
            maxRetries: maxRetries,
            preAction: async () => {
                await this.page.reload();
                await (0, test_1.expect)(this.cluster(name).first()).toBeVisible({ timeout: 60000 });
            },
        });
        console.log('Cluster is healthy:', name);
    }
    async clickAlphaTab() {
        await this.alphaTab.click();
    }
    async clickDevTab() {
        await (0, test_1.expect)(this.devTab).toBeVisible({ timeout: 30000 });
        await this.devTab.click();
    }
    async clickStableTab() {
        await this.stableTab.click();
    }
    async clickQAGenerationsTab() {
        await this.qaGenerationsTab.click();
    }
    async clickGCPRegion() {
        const regionSelectionEnabled = process.env.REGION_SELECTION === 'true';
        if (regionSelectionEnabled) {
            await (0, test_1.expect)(this.gcpRegion).toBeVisible({ timeout: 40000 });
            await this.gcpRegion.click();
        }
    }
    async clickTasklistV1Api() {
        try {
            await (0, test_1.expect)(this.tasklistV1Api).toBeVisible({ timeout: 60000 });
            await this.tasklistV1Api.click({ timeout: 30000 });
        }
        catch {
            return;
        }
    }
}
exports.ClusterPage = ClusterPage;
