"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.takeDomSnapshots = void 0;
const take_dom_snapshot_1 = require("./take-dom-snapshot");
const generate_safe_selectors_1 = require("./generate-safe-selectors");
const wait_for_lazy_load_1 = require("../../automation/utils/wait-for-lazy-load");
const chalk_1 = __importDefault(require("chalk"));
const utils = __importStar(require("@applitools/utils"));
const lang = __importStar(require("../../lang"));
__exportStar(require("./take-dom-snapshot"), exports);
async function takeDomSnapshots({ driver, settings, hooks, provides, logger, }) {
    var _a, _b, _c;
    // calculating cookies here once so that we (a) don't do it for each dom snapshot, and (b) do it before generating safe selectors
    const features = await driver.getFeatures();
    settings.cookies = features.allCookies ? await driver.getCookies().catch(() => []) : [];
    settings.lazyLoad = settings.lazyLoad !== true ? settings.lazyLoad : {};
    const currentContext = driver.currentContext;
    if (!((_a = settings.layoutBreakpoints) === null || _a === void 0 ? void 0 : _a.breakpoints)) {
        if (settings.lazyLoad) {
            await (0, wait_for_lazy_load_1.waitForLazyLoad)({ context: currentContext, settings: settings.lazyLoad, logger });
        }
        logger.log(`taking single dom snapshot`);
        await beforeEachSnapshot();
        // it's important that we calculate safe selectors as close as possible to taking the dom snapshot
        let safeSelectorResult;
        if (settings.elementReferences) {
            safeSelectorResult = await (0, generate_safe_selectors_1.generateSafeSelectors)({
                context: currentContext,
                elementReferences: settings.elementReferences,
            });
        }
        const snapshot = await (0, take_dom_snapshot_1.takeDomSnapshot)({ context: currentContext, settings, logger });
        await ((_b = safeSelectorResult === null || safeSelectorResult === void 0 ? void 0 : safeSelectorResult.cleanupGeneratedSelectors) === null || _b === void 0 ? void 0 : _b.call(safeSelectorResult));
        return Array(settings.environments.length).fill({ ...snapshot, generatedSelectors: safeSelectorResult === null || safeSelectorResult === void 0 ? void 0 : safeSelectorResult.selectors });
    }
    const isStrictBreakpoints = utils.types.isArray((_c = settings.layoutBreakpoints) === null || _c === void 0 ? void 0 : _c.breakpoints);
    const requiredWidths = await settings.environments.reduce(async (prev, environment, index) => {
        const { name, width } = (await extractEnvironmentInfo(environment));
        const requiredWidths = await prev;
        const requiredWidth = isStrictBreakpoints
            ? calculateBreakpoint({ breakpoints: settings.layoutBreakpoints.breakpoints, value: width })
            : width;
        let environments = requiredWidths.get(requiredWidth);
        if (!environments)
            requiredWidths.set(requiredWidth, (environments = []));
        environments.push({ name, width, index });
        return requiredWidths;
    }, Promise.resolve(new Map()));
    const smallestBreakpoint = Math.min(...(isStrictBreakpoints ? settings.layoutBreakpoints.breakpoints : []));
    if (isStrictBreakpoints && requiredWidths.has(smallestBreakpoint - 1)) {
        const message = lang.requestedEnvironmentSmallerThenBreakpointWarning({
            breakpoint: smallestBreakpoint,
            browsers: requiredWidths.get(smallestBreakpoint - 1),
        });
        logger.console.log(chalk_1.default.yellow(message));
    }
    logger.log(`Taking multiple dom snapshots for the breakpoints`, settings.layoutBreakpoints);
    const initialViewportSize = await driver.getViewportSize();
    const entries = [];
    const initialsBrowsers = requiredWidths.get(initialViewportSize.width);
    if (initialsBrowsers) {
        logger.log(`The first dom snapshot is going to be taking for initial viewport size`, initialViewportSize);
        requiredWidths.delete(initialViewportSize.width);
        entries.push({ browsers: initialsBrowsers });
    }
    requiredWidths.forEach((browsers, requiredWidth) => entries.push({ viewportSize: { width: requiredWidth, height: initialViewportSize.height }, browsers }));
    logger.log(`All entries to take dom snapshots for`, entries);
    let safeSelectorResult;
    const snapshots = Array(settings.environments.length);
    for (const [index, { viewportSize, browsers }] of entries.entries()) {
        logger.log(`Taking dom snapshot for viewport size ${viewportSize}`);
        if (viewportSize) {
            try {
                await driver.setViewportSize(viewportSize);
            }
            catch (error) {
                logger.error(`Failed to set viewport size to ${viewportSize} due to the error`, error);
                const actualViewportSize = await driver.getViewportSize();
                if (isStrictBreakpoints) {
                    const message = lang.breakpointOutOfDriverBoundsWarning({
                        requiredWidth: viewportSize.width,
                        actualWidth: actualViewportSize.width,
                        browsers,
                    });
                    logger.console.log(chalk_1.default.yellow(message));
                    logger.log(message);
                }
                else {
                    const message = lang.requestedEnvironmentOutOfDriverBoundsWarning({
                        requiredWidth: viewportSize.width,
                        actualWidth: actualViewportSize.width,
                        browsers,
                    });
                    logger.console.log(chalk_1.default.yellow(message));
                    logger.log(message);
                }
            }
        }
        if (settings.layoutBreakpoints.reload)
            await driver.reloadPage();
        if (settings.lazyLoad && (index === 0 || settings.layoutBreakpoints.reload)) {
            await (0, wait_for_lazy_load_1.waitForLazyLoad)({ context: currentContext, settings: settings.lazyLoad, logger });
        }
        await beforeEachSnapshot();
        // it's important that we calculate safe selectors as close as possible to taking the dom snapshot
        if (settings.elementReferences && (index === 0 || settings.layoutBreakpoints.reload)) {
            safeSelectorResult = await (0, generate_safe_selectors_1.generateSafeSelectors)({
                context: currentContext,
                elementReferences: settings.elementReferences,
            });
        }
        const snapshot = await (0, take_dom_snapshot_1.takeDomSnapshot)({ context: currentContext, settings, logger });
        browsers.forEach(({ index }) => (snapshots[index] = { ...snapshot, generatedSelectors: safeSelectorResult === null || safeSelectorResult === void 0 ? void 0 : safeSelectorResult.selectors }));
    }
    await driver.setViewportSize(initialViewportSize);
    if (settings.layoutBreakpoints.reload) {
        await driver.reloadPage();
        await beforeEachSnapshot();
    }
    else {
        await (safeSelectorResult === null || safeSelectorResult === void 0 ? void 0 : safeSelectorResult.cleanupGeneratedSelectors());
    }
    return snapshots;
    async function beforeEachSnapshot() {
        var _a, _b;
        await ((_a = hooks === null || hooks === void 0 ? void 0 : hooks.beforeEachSnapshot) === null || _a === void 0 ? void 0 : _a.call(hooks));
        if (utils.types.isNumber(settings.waitBeforeCapture)) {
            await utils.general.sleep(settings.waitBeforeCapture);
        }
        else {
            await ((_b = settings.waitBeforeCapture) === null || _b === void 0 ? void 0 : _b.call(settings));
        }
    }
    function calculateBreakpoint({ breakpoints, value }) {
        const nextBreakpointIndex = breakpoints
            .sort((item1, item2) => (item1 > item2 ? 1 : -1))
            .findIndex(breakpoint => breakpoint > value);
        if (nextBreakpointIndex === -1)
            return breakpoints[breakpoints.length - 1];
        else if (nextBreakpointIndex === 0)
            return breakpoints[0] - 1;
        else
            return breakpoints[nextBreakpointIndex - 1];
    }
    async function extractEnvironmentInfo(environment) {
        if (utils.types.has(environment, ['width', 'height'])) {
            const { name, width, height } = environment;
            return { name: name !== null && name !== void 0 ? name : 'default', width, height };
        }
        else if (utils.types.has(environment, 'chromeEmulationInfo')) {
            const devices = await provides.getChromeEmulationDevices();
            const { deviceName, screenOrientation = 'portrait' } = environment.chromeEmulationInfo;
            return { name: deviceName, screenOrientation, ...devices[deviceName][screenOrientation] };
        }
        else if (utils.types.has(environment, 'iosDeviceInfo')) {
            const devices = await provides.getIOSDevices();
            const { deviceName, screenOrientation = 'portrait' } = environment.iosDeviceInfo;
            return { name: deviceName, screenOrientation, ...devices[deviceName][screenOrientation] };
        }
    }
}
exports.takeDomSnapshots = takeDomSnapshots;
