"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserScreenshotObserver = void 0;
const ObservationDispatcher_1 = require("./ObservationDispatcher");
const execution_1 = require("../execution");
const ScreenshotObserver_1 = require("./ScreenshotObserver");
const fs_1 = require("fs");
const loggingProvider_1 = require("../providers/logging/loggingProvider");
const browserLauncher_1 = require("../browserLauncher");
const asyncUtil_1 = require("../util/asyncUtil");
const errorUtil_1 = require("../util/errorUtil");
const path_1 = __importDefault(require("path"));
const BOUNDING_BOX_MAX_WAIT_TIME_MS = 25_000;
const PLAYWRIGHT_SCREENSHOT_TIMEOUT = 20_000;
const DOM_CONTENT_LOADED_TIMEOUT = 20_000;
const CDP_SCREENSHOT_TIMEOUT = 10_000;
const BBOX_SCRIPT_PATH = path_1.default.resolve(__dirname, '../resources/captureBBoxesCompiled.js');
class BrowserScreenshotObserver extends ScreenshotObserver_1.ScreenshotObserver {
    constructor(bboxCaptureEnabled, minBoundingBoxArea, dispatcher, isCloudRun = false) {
        super(bboxCaptureEnabled, minBoundingBoxArea, dispatcher, isCloudRun);
        this.useFallbackScreenshotCall = false;
        if (this.bboxCaptureEnabled) {
            this.boundingBoxesFunction = this.getBoundingBoxFunction();
        }
    }
    getBoundingBoxFunction() {
        try {
            return (0, fs_1.readFileSync)(BBOX_SCRIPT_PATH, 'utf8');
        }
        catch (e) {
            loggingProvider_1.logger.error(`Error reading bounding box script file: ${e}`);
            return undefined;
        }
    }
    async captureScreenshot(observerContext) {
        const { executionContext } = observerContext;
        const page = executionContext.pageFrameContext.getCurrentPage();
        const screenshot = this.useFallbackScreenshotCall
            ? await this.takeFallbackScreenshot(observerContext, page)
            : await this.takePlaywrightScreenshot(observerContext, page);
        if (!screenshot) {
            loggingProvider_1.logger.warn(`No screenshot data captured of current page [${executionContext.maybeGetCurrentUrl()}]`);
        }
        return screenshot;
    }
    async takePlaywrightScreenshot(context, page) {
        try {
            await page.waitForLoadState({
                waitUntil: browserLauncher_1.LifecycleEvent.DomContentLoaded,
                timeout: DOM_CONTENT_LOADED_TIMEOUT,
            });
            return await page.screenshot({ timeout: PLAYWRIGHT_SCREENSHOT_TIMEOUT });
        }
        catch (error) {
            const currentUrl = context.executionContext.maybeGetCurrentUrl();
            loggingProvider_1.logger.error(`Failed to take screenshot of current page [${currentUrl}] with Error: ${error}`);
            this.useFallbackScreenshotCall = true;
            return this.takeFallbackScreenshot(context, page);
        }
    }
    async takeFallbackScreenshot(context, page) {
        loggingProvider_1.logger.info('Previous screenshot timeout detected, attempting screenshot capture with fallback [Page.captureScreenshot] CDP call');
        try {
            return this.takeCdpScreenshot(page);
        }
        catch (error) {
            const currentUrl = context.executionContext.maybeGetCurrentUrl();
            loggingProvider_1.logger.warn(`Failed to take screenshot of [${currentUrl}] with direct CDP call: Error [${error}]`);
            if (error instanceof asyncUtil_1.TimeoutError) {
                loggingProvider_1.logger.info('Previous screenshot attempt timed out, possibly due to page navigation. Reattempting direct CDP call');
                try {
                    return this.takeCdpScreenshot(page);
                }
                catch (error) {
                    loggingProvider_1.logger.warn('Failed twice attempting to take direct CDP screenshot. No screenshot will be available');
                }
            }
            return;
        }
    }
    async takeCdpScreenshot(page) {
        const screenshot = await (0, asyncUtil_1.promiseWithTimeout)(page.makeCDPCall('Page.captureScreenshot'), CDP_SCREENSHOT_TIMEOUT, 'cdp screenshot');
        return Buffer.from(screenshot.data, 'base64');
    }
    async captureBoundingBox(observerContext) {
        const boundingBoxesFunction = this.boundingBoxesFunction;
        if (!boundingBoxesFunction) {
            return;
        }
        const { executionContext } = observerContext;
        const page = executionContext.pageFrameContext.getCurrentPage();
        return (0, execution_1.runWithRetries)(() => page.evaluateCodeInSecondaryWorld(({ boundingBoxesFunction, minBoundingBoxArea }) => {
            eval(boundingBoxesFunction);
            return mabl_execution_engine.extractElementBBoxes(minBoundingBoxArea, false);
        }, {
            boundingBoxesFunction,
            minBoundingBoxArea: this.minBoundingBoxArea,
        }), ObservationDispatcher_1.MAX_RETRIES, errorUtil_1.STRINGS_TO_RETRY_ON, executionContext, ObservationDispatcher_1.MIN_TIMEOUT_MS, ObservationDispatcher_1.MAX_TIMEOUT_MS, BOUNDING_BOX_MAX_WAIT_TIME_MS);
    }
    getScaleFactor(context) {
        const page = context.executionContext.pageFrameContext.getCurrentPage();
        return page.evaluateCodeInSecondaryWorld(() => globalThis.devicePixelRatio);
    }
}
exports.BrowserScreenshotObserver = BrowserScreenshotObserver;
