"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments)).next());
    });
};
const constants = require("../constants");
const semver = require("semver");
const path = require("path");
const helpers_1 = require("../common/helpers");
class VersionsService {
    constructor($fs, $npmInstallationManager, $injector, $staticConfig, $pluginsService) {
        this.$fs = $fs;
        this.$npmInstallationManager = $npmInstallationManager;
        this.$injector = $injector;
        this.$staticConfig = $staticConfig;
        this.$pluginsService = $pluginsService;
        this.projectData = this.getProjectData();
    }
    getNativescriptCliVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            let currentCliVersion = this.$staticConfig.version;
            let latestCliVersion = yield this.$npmInstallationManager.getLatestVersion(constants.NATIVESCRIPT_KEY_NAME);
            return {
                componentName: constants.NATIVESCRIPT_KEY_NAME,
                currentVersion: currentCliVersion,
                latestVersion: latestCliVersion
            };
        });
    }
    getTnsCoreModulesVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            let latestTnsCoreModulesVersion = yield this.$npmInstallationManager.getLatestVersion(constants.TNS_CORE_MODULES_NAME);
            let nativescriptCoreModulesInfo = {
                componentName: constants.TNS_CORE_MODULES_NAME,
                latestVersion: latestTnsCoreModulesVersion
            };
            if (this.projectData) {
                let nodeModulesPath = path.join(this.projectData.projectDir, constants.NODE_MODULES_FOLDER_NAME);
                let tnsCoreModulesPath = path.join(nodeModulesPath, constants.TNS_CORE_MODULES_NAME);
                if (!this.$fs.exists(nodeModulesPath) ||
                    !this.$fs.exists(tnsCoreModulesPath)) {
                    yield this.$pluginsService.ensureAllDependenciesAreInstalled();
                }
                let currentTnsCoreModulesVersion = this.$fs.readJson(path.join(tnsCoreModulesPath, constants.PACKAGE_JSON_FILE_NAME)).version;
                nativescriptCoreModulesInfo.currentVersion = currentTnsCoreModulesVersion;
            }
            return nativescriptCoreModulesInfo;
        });
    }
    getRuntimesVersions() {
        return __awaiter(this, void 0, void 0, function* () {
            let runtimes = [
                constants.TNS_ANDROID_RUNTIME_NAME,
                constants.TNS_IOS_RUNTIME_NAME
            ];
            let projectConfig;
            if (this.projectData) {
                projectConfig = this.$fs.readJson(this.projectData.projectFilePath);
            }
            let runtimesVersions = yield Promise.all(runtimes.map((runtime) => __awaiter(this, void 0, void 0, function* () {
                let latestRuntimeVersion = yield this.$npmInstallationManager.getLatestVersion(runtime);
                let runtimeInformation = {
                    componentName: runtime,
                    latestVersion: latestRuntimeVersion
                };
                if (projectConfig) {
                    let projectRuntimeInformation = projectConfig.nativescript && projectConfig.nativescript[runtime];
                    if (projectRuntimeInformation) {
                        let runtimeVersionInProject = projectRuntimeInformation.version;
                        runtimeInformation.currentVersion = runtimeVersionInProject;
                    }
                }
                return runtimeInformation;
            })));
            return runtimesVersions;
        });
    }
    getComponentsForUpdate() {
        return __awaiter(this, void 0, void 0, function* () {
            let allComponents = yield this.getAllComponentsVersions();
            let componentsForUpdate = [];
            _.forEach(allComponents, (component) => {
                if (component.currentVersion && this.hasUpdate(component)) {
                    componentsForUpdate.push(component);
                }
            });
            return componentsForUpdate;
        });
    }
    getAllComponentsVersions() {
        return __awaiter(this, void 0, void 0, function* () {
            let allComponents = [];
            let nativescriptCliInformation = yield this.getNativescriptCliVersion();
            if (nativescriptCliInformation) {
                allComponents.push(nativescriptCliInformation);
            }
            let nativescriptCoreModulesInformation = yield this.getTnsCoreModulesVersion();
            if (nativescriptCoreModulesInformation) {
                allComponents.push(nativescriptCoreModulesInformation);
            }
            let runtimesVersions = yield this.getRuntimesVersions();
            allComponents = allComponents.concat(runtimesVersions);
            return allComponents;
        });
    }
    createTableWithVersionsInformation(versionsInformation) {
        let headers = ["Component", "Current version", "Latest version", "Information"];
        let data = [];
        _.forEach(versionsInformation, (componentInformation) => {
            let row = [
                componentInformation.componentName,
                componentInformation.currentVersion,
                componentInformation.latestVersion
            ];
            if (componentInformation.currentVersion) {
                semver.lt(componentInformation.currentVersion, componentInformation.latestVersion) ? row.push(VersionsService.UPDATE_AVAILABLE_MESSAGE) : row.push(VersionsService.UP_TO_DATE_MESSAGE);
            }
            else {
                row.push(VersionsService.NOT_INSTALLED_MESSAGE);
            }
            data.push(row);
        });
        return helpers_1.createTable(headers, data);
    }
    getProjectData() {
        try {
            return this.$injector.resolve("projectData");
        }
        catch (error) {
            return null;
        }
    }
    hasUpdate(component) {
        return semver.lt(component.currentVersion, component.latestVersion);
    }
}
VersionsService.UP_TO_DATE_MESSAGE = "Up to date".green.toString();
VersionsService.UPDATE_AVAILABLE_MESSAGE = "Update available".yellow.toString();
VersionsService.NOT_INSTALLED_MESSAGE = "Not installed".grey.toString();
$injector.register("versionsService", VersionsService);
