"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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeCheck = void 0;
const nml_client_1 = require("@applitools/nml-client");
const driver_1 = require("@applitools/driver");
const take_screenshots_1 = require("./utils/take-screenshots");
const to_base_check_settings_1 = require("../automation/utils/to-base-check-settings");
const wait_for_lazy_load_1 = require("../automation/utils/wait-for-lazy-load");
const uniquify_environments_1 = require("../automation/utils/uniquify-environments");
const to_environment_key_1 = require("../automation/utils/to-environment-key");
const abort_error_1 = require("../errors/abort-error");
const chalk_1 = __importDefault(require("chalk"));
const utils = __importStar(require("@applitools/utils"));
const lang = __importStar(require("../lang"));
function makeCheck({ eyes, target: defaultTarget, environments: defaultEnvironments = [], spec, signal, logger: mainLogger, }) {
    return async function check({ target = defaultTarget, settings = {}, logger = mainLogger, } = {}) {
        var _a, _b, _c;
        logger = logger.extend(mainLogger);
        logger.log('Command "check" is called with settings', settings);
        if (!target)
            throw new Error('Method was called with no target');
        if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
            logger.warn('Command "check" was called after test was already aborted');
            throw new abort_error_1.AbortError('Command "check" was called after test was already aborted');
        }
        const uniqueEnvironments = (0, uniquify_environments_1.uniquifyEnvironments)((_a = settings.environments) !== null && _a !== void 0 ? _a : defaultEnvironments);
        const baseTargets = [];
        const baseSettings = [];
        const exactEnvironments = [];
        if ((0, driver_1.isDriver)(target, spec)) {
            const driver = await (0, driver_1.makeDriver)({ spec, driver: target, reset: target === defaultTarget, logger });
            await driver.currentContext.setScrollingElement((_b = settings.scrollRootElement) !== null && _b !== void 0 ? _b : null);
            const driverEnvironment = await driver.getEnvironment();
            uniqueEnvironments.forEach(environment => {
                var _a, _b;
                var _c, _d;
                if (utils.types.has(environment, 'iosDeviceInfo')) {
                    (_a = (_c = environment.iosDeviceInfo).version) !== null && _a !== void 0 ? _a : (_c.version = driverEnvironment.platformVersion);
                }
                else if (utils.types.has(environment, 'androidDeviceInfo')) {
                    (_b = (_d = environment.androidDeviceInfo).version) !== null && _b !== void 0 ? _b : (_d.version = driverEnvironment.platformVersion);
                }
                return environment;
            });
            if (settings.lazyLoad && driverEnvironment.isWeb) {
                await (0, wait_for_lazy_load_1.waitForLazyLoad)({
                    context: driver.currentContext,
                    settings: settings.lazyLoad !== true ? settings.lazyLoad : {},
                    logger,
                });
            }
            if (driverEnvironment.isWeb ||
                !((_c = driverEnvironment.applitoolsLib) === null || _c === void 0 ? void 0 : _c.instrumented) ||
                settings.webview ||
                settings.screenshotMode === 'default') {
                let actualEnvironments = uniqueEnvironments;
                if (settings.screenshotMode === 'default') {
                    const { localEnvironment, renderEnvironments } = await (0, nml_client_1.getNMLEnvironmentsInfo)({
                        environments: uniqueEnvironments,
                        supportedEnvironmentsUrl: eyes.test.supportedEnvironmentsUrl,
                        proxy: eyes.test.eyesServer.proxy,
                        logger,
                    });
                    actualEnvironments = localEnvironment ? [localEnvironment] : renderEnvironments;
                }
                const { elementReferences, getBaseCheckSettings } = (0, to_base_check_settings_1.toBaseCheckSettings)({ settings });
                const screenshots = await (0, take_screenshots_1.takeScreenshots)({
                    driver,
                    settings: {
                        ...settings,
                        environments: actualEnvironments,
                        regionsToCalculate: elementReferences.calculate,
                        calculateView: !!settings.pageId,
                        domSettings: settings.sendDom ? { proxy: eyes.test.eyesServer.proxy } : undefined,
                    },
                    logger,
                });
                exactEnvironments.push(...actualEnvironments);
                screenshots.forEach(({ calculatedRegions, ...baseTarget }) => {
                    baseTargets.push(baseTarget);
                    baseSettings.push(getBaseCheckSettings({ calculatedRegions }));
                });
            }
            else {
                if (driverEnvironment.applitoolsLib.conflictingCapabilities) {
                    const message = lang.applitoolsLibConflictingCapabilitiesWarning({
                        conflictingCapabilities: driverEnvironment.applitoolsLib.conflictingCapabilities,
                    });
                    logger.console.log(chalk_1.default.yellow(message));
                    logger.log(message);
                }
                const nmlClient = await eyes.core.getNMLClient({
                    driver,
                    settings: { ...eyes.test.eyesServer, supportedEnvironmentsUrl: eyes.test.supportedEnvironmentsUrl },
                    logger,
                });
                if (settings.scrollRootElement || settings.region || (0, to_base_check_settings_1.hasCodedRegions)(settings))
                    await nmlClient.preTakeScreenshot({ logger });
                const { elementReferences, getBaseCheckSettings } = (0, to_base_check_settings_1.toBaseCheckSettings)({
                    settings: {
                        ...settings,
                        ...(await (0, to_base_check_settings_1.extractMobileElementsIntoCheckSettings)({ settings, driver, logger })),
                    },
                });
                const calculate = elementReferences.calculate;
                const screenshots = await nmlClient.takeScreenshots({
                    settings: {
                        environments: uniqueEnvironments,
                        fully: settings.fully,
                        stitchMode: settings.stitchMode,
                        hideScrollbars: settings.hideScrollbars,
                        hideCaret: settings.hideScrollbars,
                        overlap: settings.overlap,
                        waitBeforeCapture: settings.waitBeforeCapture,
                        waitBetweenStitches: settings.waitBetweenStitches,
                        lazyLoad: settings.lazyLoad,
                        name: settings.name,
                        region: elementReferences.target,
                        selectorsToFindRegionsFor: calculate.map(({ name }) => name),
                        scrollRootElement: elementReferences.scrolling,
                    },
                    logger,
                });
                screenshots.forEach(({ environment, calculateRegions, ...baseTarget }) => {
                    const aggregateCalculatedRegions = [];
                    calculate.forEach(({ reference }, index) => {
                        const regions = calculateRegions === null || calculateRegions === void 0 ? void 0 : calculateRegions[index];
                        if (regions) {
                            aggregateCalculatedRegions.push({ regions, selector: reference });
                        }
                        else {
                            logger.log(`Regions "${reference}" was not found in the screenshot`);
                        }
                    });
                    exactEnvironments.push(environment);
                    baseTargets.push({ ...baseTarget, isTransformed: true });
                    baseSettings.push(getBaseCheckSettings({
                        calculatedRegions: aggregateCalculatedRegions,
                    }));
                });
            }
        }
        else {
            exactEnvironments.push(...uniqueEnvironments);
            baseTargets.push(target);
            baseSettings.push(settings);
        }
        const promises = exactEnvironments.map(async (environment, index) => {
            var _a, _b, _c;
            const environmentLogger = logger.extend({ tags: [`environment-${utils.general.shortid()}`] });
            try {
                if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
                    environmentLogger.warn('Command "check" was aborted before checking');
                    throw new abort_error_1.AbortError('Command "check" was aborted before checking');
                }
                const baseEyes = await eyes.getBaseEyes({ settings: { environment }, logger: environmentLogger });
                try {
                    if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
                        environmentLogger.warn('Command "check" was aborted before checking');
                        throw new abort_error_1.AbortError('Command "check" was aborted before checking');
                    }
                    else if (!baseEyes.running) {
                        environmentLogger.warn(`Check on environment with id "${(_a = baseEyes.test.environment) === null || _a === void 0 ? void 0 : _a.environmentId}" was aborted during one of the previous steps`);
                        throw new abort_error_1.AbortError(`Check on environment with id "${(_b = baseEyes.test.environment) === null || _b === void 0 ? void 0 : _b.environmentId}" was aborted during one of the previous steps`);
                    }
                    await baseEyes.check({
                        target: baseTargets[index],
                        settings: baseSettings[index],
                        logger: environmentLogger,
                    });
                }
                catch (error) {
                    environmentLogger.error(`Check on environment with id "${(_c = baseEyes.test.environment) === null || _c === void 0 ? void 0 : _c.environmentId}" failed due to an error`, error);
                    if (baseEyes.running && !(signal === null || signal === void 0 ? void 0 : signal.aborted))
                        await baseEyes.abort({ logger: environmentLogger, settings: { reason: error } });
                }
            }
            catch (error) {
                environmentLogger.error(`Environment with id ${environment.environmentId} failed before checking started due to an error`, error);
                error.info = { ...error.info, userTestId: eyes.test.userTestId, environment };
                throw error;
            }
        });
        exactEnvironments.forEach((environment, index) => {
            const key = (0, to_environment_key_1.toEnvironmentKey)(environment);
            let item = eyes.storage.get(key);
            if (!item) {
                item = { eyes: utils.promises.makeControlledPromise(), jobs: [] };
                eyes.storage.set(key, item);
            }
            item.jobs.push(promises[index]);
        });
    };
}
exports.makeCheck = makeCheck;
