var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { chromium, firefox, } from "playwright";
import LocalFile from "./LocalFile";
import BadDataException from "../../Types/Exception/BadDataException";
import ScreenSizeType from "../../Types/ScreenSizeType";
import BrowserType from "../../Types/BrowserType";
import logger from "./Logger";
import CaptureSpan from "./Telemetry/CaptureSpan";
import os from "os";
class BrowserUtil {
    static async convertHtmlToBase64Screenshot(data) {
        try {
            const html = data.html;
            const pageAndBrowser = await BrowserUtil.getPageByBrowserType({
                browserType: BrowserType.Chromium,
                screenSizeType: ScreenSizeType.Desktop,
            });
            const page = pageAndBrowser.page;
            const browser = pageAndBrowser.browser;
            await page.setContent(html, {
                waitUntil: "domcontentloaded",
            });
            const screenshot = await page.screenshot({ type: "png" });
            await browser.close();
            return screenshot.toString("base64");
        }
        catch (e) {
            logger.debug(e);
            return null;
        }
    }
    static async getPageByBrowserType(data) {
        const viewport = BrowserUtil.getViewportHeightAndWidth({
            screenSizeType: data.screenSizeType,
        });
        let page = null;
        let browser = null;
        if (data.browserType === BrowserType.Chromium) {
            browser = await chromium.launch({
                executablePath: await BrowserUtil.getChromeExecutablePath(),
                headless: true,
                args: BrowserUtil.chromiumStabilityArgs,
            });
            page = await browser.newPage();
        }
        if (data.browserType === BrowserType.Firefox) {
            browser = await firefox.launch({
                executablePath: await BrowserUtil.getFirefoxExecutablePath(),
                headless: true,
                firefoxUserPrefs: BrowserUtil.firefoxStabilityPrefs,
            });
            page = await browser.newPage();
        }
        /*
         * if (data.browserType === BrowserType.Webkit) {
         *     browser = await webkit.launch();
         *     page = await browser.newPage();
         * }
         */
        await (page === null || page === void 0 ? void 0 : page.setViewportSize({
            width: viewport.width,
            height: viewport.height,
        }));
        if (!browser) {
            throw new BadDataException("Invalid Browser Type.");
        }
        if (!page) {
            // close the browser if page is not created
            await browser.close();
            throw new BadDataException("Invalid Browser Type.");
        }
        return {
            page: page,
            browser: browser,
        };
    }
    static getViewportHeightAndWidth(options) {
        let viewPortHeight = 0;
        let viewPortWidth = 0;
        switch (options.screenSizeType) {
            case ScreenSizeType.Desktop:
                viewPortHeight = 1080;
                viewPortWidth = 1920;
                break;
            case ScreenSizeType.Mobile:
                viewPortHeight = 640;
                viewPortWidth = 360;
                break;
            case ScreenSizeType.Tablet:
                viewPortHeight = 768;
                viewPortWidth = 1024;
                break;
            default:
                viewPortHeight = 1080;
                viewPortWidth = 1920;
                break;
        }
        return { height: viewPortHeight, width: viewPortWidth };
    }
    static getPlaywrightBrowsersPath() {
        return (process.env["PLAYWRIGHT_BROWSERS_PATH"] ||
            `${os.homedir()}/.cache/ms-playwright`);
    }
    static async getChromeExecutablePath() {
        const browsersPath = this.getPlaywrightBrowsersPath();
        const doesDirectoryExist = await LocalFile.doesDirectoryExist(browsersPath);
        if (!doesDirectoryExist) {
            throw new BadDataException("Chrome executable path not found.");
        }
        // get list of files in the directory
        const directories = await LocalFile.getListOfDirectories(browsersPath);
        if (directories.length === 0) {
            throw new BadDataException("Chrome executable path not found.");
        }
        const chromeInstallationName = directories.find((directory) => {
            return directory.includes("chromium");
        });
        if (!chromeInstallationName) {
            throw new BadDataException("Chrome executable path not found.");
        }
        const chromeExecutableCandidates = [
            `${browsersPath}/${chromeInstallationName}/chrome-linux/chrome`,
            `${browsersPath}/${chromeInstallationName}/chrome-linux64/chrome`,
            `${browsersPath}/${chromeInstallationName}/chrome64/chrome`,
            `${browsersPath}/${chromeInstallationName}/chrome/chrome`,
        ];
        for (const executablePath of chromeExecutableCandidates) {
            if (await LocalFile.doesFileExist(executablePath)) {
                return executablePath;
            }
        }
        throw new BadDataException("Chrome executable path not found.");
    }
    static async getFirefoxExecutablePath() {
        const browsersPath = this.getPlaywrightBrowsersPath();
        const doesDirectoryExist = await LocalFile.doesDirectoryExist(browsersPath);
        if (!doesDirectoryExist) {
            throw new BadDataException("Firefox executable path not found.");
        }
        // get list of files in the directory
        const directories = await LocalFile.getListOfDirectories(browsersPath);
        if (directories.length === 0) {
            throw new BadDataException("Firefox executable path not found.");
        }
        const firefoxInstallationName = directories.find((directory) => {
            return directory.includes("firefox");
        });
        if (!firefoxInstallationName) {
            throw new BadDataException("Firefox executable path not found.");
        }
        const firefoxExecutableCandidates = [
            `${browsersPath}/${firefoxInstallationName}/firefox/firefox`,
            `${browsersPath}/${firefoxInstallationName}/firefox-linux64/firefox`,
            `${browsersPath}/${firefoxInstallationName}/firefox64/firefox`,
            `${browsersPath}/${firefoxInstallationName}/firefox-64/firefox`,
        ];
        for (const executablePath of firefoxExecutableCandidates) {
            if (await LocalFile.doesFileExist(executablePath)) {
                return executablePath;
            }
        }
        throw new BadDataException("Firefox executable path not found.");
    }
}
// Chromium arguments for stability and memory optimization in containerized environments
BrowserUtil.chromiumStabilityArgs = [
    "--no-sandbox",
    "--disable-setuid-sandbox",
    "--disable-dev-shm-usage",
    "--disable-gpu",
    "--disable-software-rasterizer",
    "--disable-dbus", // no D-Bus daemon in containers
    "--disable-features=dbus", // additional D-Bus feature gate
    "--no-zygote", // skip zygote process that fails OOM score adjustments in containers
    // Memory optimization flags
    "--disable-extensions", // no extensions needed for monitoring
    "--disable-background-networking", // disable background network requests
    "--disable-default-apps", // don't load default apps
    "--disable-sync", // no sync needed
    "--disable-translate", // no translation needed
    "--disable-backgrounding-occluded-windows", // don't throttle hidden windows
    "--disable-renderer-backgrounding", // don't background renderers
    "--disable-background-timer-throttling", // don't throttle timers
    "--disable-ipc-flooding-protection", // allow high IPC throughput
    "--memory-pressure-off", // disable memory pressure signals that cause GC
    "--js-flags=--max-old-space-size=256", // limit V8 heap to 256MB
    "--disable-features=TranslateUI,BlinkGenPropertyTrees", // disable unused features
    "--disable-component-update", // don't update components
    "--disable-domain-reliability", // no domain reliability monitoring
    "--disable-client-side-phishing-detection", // no phishing detection
    "--no-first-run", // skip first run experience
    "--disable-hang-monitor", // no hang monitor
    "--disable-popup-blocking", // allow popups for testing
    "--disable-prompt-on-repost", // no repost prompts
    "--metrics-recording-only", // disable metrics uploading
    "--safebrowsing-disable-auto-update", // no safe browsing updates
];
// Firefox preferences for stability and memory optimization in containerized environments
BrowserUtil.firefoxStabilityPrefs = {
    "gfx.webrender.all": false, // disable GPU-based WebRender
    "media.hardware-video-decoding.enabled": false, // disable hardware video decoding
    "layers.acceleration.disabled": true, // disable GPU-accelerated layers
    "network.http.spdy.enabled.http2": true, // keep HTTP/2 enabled
    // Memory optimization preferences
    "javascript.options.mem.max": 256 * 1024, // limit JS memory to 256MB in KB
    "javascript.options.mem.high_water_mark": 128, // GC high water mark in MB
    "browser.cache.memory.capacity": 16384, // limit memory cache to 16MB
    "browser.cache.disk.enable": false, // disable disk cache
    "browser.sessionhistory.max_entries": 3, // limit session history
    "browser.sessionhistory.max_total_viewers": 0, // don't keep pages in bfcache
    "dom.ipc.processCount": 1, // single content process
    "extensions.update.enabled": false, // no extension updates
    "network.prefetch-next": false, // no prefetching
    "network.dns.disablePrefetch": true, // no DNS prefetch
    "network.http.speculative-parallel-limit": 0, // no speculative connections
    "browser.tabs.remote.autostart": false, // disable multi-process
    "media.peerconnection.enabled": false, // disable WebRTC
    "media.navigator.enabled": false, // disable getUserMedia
};
export default BrowserUtil;
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], BrowserUtil, "convertHtmlToBase64Screenshot", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], BrowserUtil, "getPageByBrowserType", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Object)
], BrowserUtil, "getViewportHeightAndWidth", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], BrowserUtil, "getChromeExecutablePath", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], BrowserUtil, "getFirefoxExecutablePath", null);
//# sourceMappingURL=Browser.js.map