"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PreviewAppPluginsService = void 0;
const path = require("path");
const semver = require("semver");
const util = require("util");
const _ = require("lodash");
const preview_app_constants_1 = require("./preview-app-constants");
const constants_1 = require("../../../common/constants");
const constants_2 = require("../../../constants");
const yok_1 = require("../../../common/yok");
class PreviewAppPluginsService {
    constructor($errors, $fs, $logger, $packageInstallationManager, $pluginsService) {
        this.$errors = $errors;
        this.$fs = $fs;
        this.$logger = $logger;
        this.$packageInstallationManager = $packageInstallationManager;
        this.$pluginsService = $pluginsService;
    }
    getPluginsUsageWarnings(data, device) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!device) {
                this.$errors.fail("No device provided.");
            }
            if (!device.previewAppVersion) {
                this.$errors.fail("No version of preview app provided.");
            }
            const devicePlugins = this.getDevicePlugins(device);
            const localPlugins = this.getLocalPlugins(data.projectDir);
            const warnings = [];
            for (const pluginName in localPlugins) {
                const localPluginVersion = localPlugins[pluginName];
                const devicePluginVersion = devicePlugins[pluginName];
                const pluginWarnings = yield this.getWarningForPlugin(data, pluginName, localPluginVersion, devicePluginVersion, device);
                if (pluginWarnings) {
                    warnings.push(pluginWarnings);
                }
            }
            return warnings;
        });
    }
    comparePluginsOnDevice(data, device) {
        return __awaiter(this, void 0, void 0, function* () {
            const warnings = yield this.getPluginsUsageWarnings(data, device);
            _.map(warnings, (warning) => this.$logger.warn(warning));
            if (warnings && warnings.length) {
                this.$logger.warn(`In the app are used one or more NativeScript plugins with native dependencies.
Those plugins will not work while building the project via \`$ tns preview\`. Please, use \`$ tns run <platform>\` command instead.`, { [constants_2.LoggerConfigData.wrapMessageWithBorders]: true });
            }
        });
    }
    getExternalPlugins(device) {
        const devicePlugins = this.getDevicePlugins(device);
        const themeNamesArray = [constants_2.TNS_CORE_THEME_NAME, constants_2.SCOPED_TNS_CORE_THEME_NAME];
        const result = _.keys(devicePlugins)
            .filter((plugin) => themeNamesArray.indexOf(plugin) === -1);
        return result;
    }
    getDevicePlugins(device) {
        try {
            return JSON.parse(device.plugins);
        }
        catch (err) {
            this.$logger.trace(`Error while parsing plugins from device ${device.id}. Error is ${err.message}`);
            return {};
        }
    }
    getLocalPlugins(projectDir) {
        const projectFilePath = path.join(projectDir, constants_2.PACKAGE_JSON_FILE_NAME);
        try {
            return this.$fs.readJson(projectFilePath).dependencies;
        }
        catch (err) {
            this.$logger.trace(`Error while parsing ${projectFilePath}. Error is ${err.message}`);
            return {};
        }
    }
    getWarningForPlugin(data, localPlugin, localPluginVersion, devicePluginVersion, device) {
        return __awaiter(this, void 0, void 0, function* () {
            const pluginPackageJsonPath = path.join(data.projectDir, constants_1.NODE_MODULES_DIR_NAME, localPlugin, constants_2.PACKAGE_JSON_FILE_NAME);
            const isNativeScriptPlugin = this.$pluginsService.isNativeScriptPlugin(pluginPackageJsonPath);
            const shouldCompare = isNativeScriptPlugin &&
                this.hasNativeCode(localPlugin, device.platform, data.projectDir);
            let warning = null;
            if (shouldCompare) {
                warning = yield this.getWarningForPluginCore(localPlugin, localPluginVersion, devicePluginVersion, device.id);
            }
            return warning;
        });
    }
    getWarningForPluginCore(pluginName, localPluginVersion, devicePluginVersion, deviceId) {
        return __awaiter(this, void 0, void 0, function* () {
            this.$logger.trace(`Comparing plugin ${pluginName} with localPluginVersion ${localPluginVersion} and devicePluginVersion ${devicePluginVersion}`);
            if (!devicePluginVersion) {
                return util.format(preview_app_constants_1.PluginComparisonMessages.PLUGIN_NOT_INCLUDED_IN_PREVIEW_APP, pluginName, deviceId);
            }
            const shouldSkipCheck = !semver.valid(localPluginVersion) &&
                !semver.validRange(localPluginVersion);
            if (shouldSkipCheck) {
                return null;
            }
            const localPluginVersionData = yield this.$packageInstallationManager.getMaxSatisfyingVersionSafe(pluginName, localPluginVersion);
            const devicePluginVersionData = yield this.$packageInstallationManager.getMaxSatisfyingVersionSafe(pluginName, devicePluginVersion);
            if (semver.valid(localPluginVersionData) &&
                semver.valid(devicePluginVersionData)) {
                if (semver.major(localPluginVersionData) !==
                    semver.major(devicePluginVersionData)) {
                    return util.format(preview_app_constants_1.PluginComparisonMessages.LOCAL_PLUGIN_WITH_DIFFERENCE_IN_MAJOR_VERSION, pluginName, localPluginVersion, devicePluginVersion);
                }
                else if (semver.minor(localPluginVersionData) >
                    semver.minor(devicePluginVersionData)) {
                    return util.format(preview_app_constants_1.PluginComparisonMessages.LOCAL_PLUGIN_WITH_GREATHER_MINOR_VERSION, pluginName, localPluginVersion, devicePluginVersion);
                }
            }
            return null;
        });
    }
    hasNativeCode(localPlugin, platform, projectDir) {
        const nativeFolderPath = path.join(projectDir, constants_1.NODE_MODULES_DIR_NAME, localPlugin, constants_2.PLATFORMS_DIR_NAME, platform.toLowerCase());
        return (this.$fs.exists(nativeFolderPath) &&
            !this.$fs.isEmptyDir(nativeFolderPath));
    }
}
exports.PreviewAppPluginsService = PreviewAppPluginsService;
yok_1.injector.register("previewAppPluginsService", PreviewAppPluginsService);
