"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 });
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const listr2_1 = require("listr2");
const I18n_1 = require("../I18n");
const install_1 = require("../../Api/install");
const devBuild_1 = require("../../bin/utils/devBuild");
const get_latest_version_1 = require("./get-latest-version");
const utils_1 = require("./utils");
const WizError_1 = require("../WizError");
const Config_1 = require("../Config");
class DependencyUpdater {
    constructor(presentationPath, passedDependencies = [], options = {}) {
        this.presentationPath = presentationPath;
        this.passedDependencies = passedDependencies;
        this.updatedDependencies = [];
        this.unavailableDependencies = [];
        this.options = Object.assign({ install: true, skip: [] }, options);
    }
    run() {
        return __awaiter(this, void 0, void 0, function* () {
            const list = this.getTasks();
            const options = {
                rendererOptions: {
                    showErrorMessage: false,
                },
            };
            const tasks = new listr2_1.Listr(list, options);
            yield tasks.run();
            return this.getUpdatedInformation();
        });
    }
    getTasks() {
        return [
            {
                title: I18n_1.default.info('SET_DEPENDENCIES'),
                task: () => __awaiter(this, void 0, void 0, function* () { return this.getDependencies(); }),
            },
            {
                title: I18n_1.default.info('LOADING_TAGS'),
                task: () => __awaiter(this, void 0, void 0, function* () {
                    yield this.setDependenciesTags();
                    this.checkForUnavailableDependencies();
                }),
            },
            {
                title: I18n_1.default.info('SET_LATEST_TAGS'),
                task: (ctx, task) => __awaiter(this, void 0, void 0, function* () {
                    const subList = this.getLatestVersionTasks();
                    return task.newListr(subList);
                }),
            },
            {
                title: I18n_1.default.info('INSTALLING_DEPENDENCIES'),
                task: () => __awaiter(this, void 0, void 0, function* () { return this.installDependencies(); }),
                enabled: () => this.isNotEmptyUpdatedDependenciesList(),
            },
            {
                title: I18n_1.default.info('DEV_BUILD_START'),
                task: () => __awaiter(this, void 0, void 0, function* () { return (0, devBuild_1.devBuild)(this.presentationPath); }),
                enabled: () => this.isNotEmptyUpdatedDependenciesList(),
            },
        ];
    }
    getDependencies() {
        return __awaiter(this, void 0, void 0, function* () {
            const packageJsonPath = (0, path_1.join)(this.presentationPath, 'package.json');
            const { dependencies } = yield (0, fs_extra_1.readJson)(packageJsonPath);
            this.dependencies = this.getDependenciesArray(dependencies)
                .map(dependency => ({
                name: dependency,
                url: dependencies[dependency],
                message: '',
            }));
        });
    }
    getDependenciesArray(dependenciesRecord) {
        const dependencies = Object.keys(dependenciesRecord);
        if (this.passedDependencies.length) {
            return this.passedDependencies.filter(dependency => dependencies.includes(dependency));
        }
        return dependencies.filter((dependency) => !this.options.skip.includes(dependency));
    }
    setDependenciesTags() {
        return __awaiter(this, void 0, void 0, function* () {
            return this.dependencies.reduce((prevUpgrade, dependency) => __awaiter(this, void 0, void 0, function* () {
                yield prevUpgrade;
                const { url, name } = dependency;
                try {
                    dependency.tags = yield (0, utils_1.getDependencyTags)(url, name, this.presentationPath);
                }
                catch (e) {
                    this.unavailableDependencies.push(name);
                }
            }), Promise.resolve());
        });
    }
    getLatestVersionTasks() {
        return this.dependencies.map(dependency => ({
            task: (ctx, task) => __awaiter(this, void 0, void 0, function* () { return this.getDependencyTag(dependency, task); }),
        }));
    }
    getDependencyTag(dependency, task) {
        return __awaiter(this, void 0, void 0, function* () {
            const { name, url, tags } = dependency;
            const version = (0, utils_1.getVersionFromUrl)(url);
            const { major } = this.options;
            const options = { name, task, major };
            const newVersion = yield (0, get_latest_version_1.getLatestVersion)(tags, version, options);
            if (newVersion === version) {
                return;
            }
            dependency.url = (0, utils_1.getDependencyUrlWithNewHash)(url, newVersion);
            dependency.message = `- ${name}: ${version || 'master'} -> ${newVersion}`;
            this.updatedDependencies.push(dependency);
        });
    }
    installDependencies() {
        return __awaiter(this, void 0, void 0, function* () {
            const installOptions = {
                cwd: this.presentationPath,
                modules: true,
                silent: true,
            };
            const dependencies = this.updatedDependencies
                .map(dependency => {
                return `${dependency.name}@${dependency.url}`;
            });
            const installAction = yield (0, install_1.createAction)(this.presentationPath);
            return installAction(dependencies, installOptions);
        });
    }
    checkForUnavailableDependencies() {
        if (!this.unavailableDependencies.length) {
            return;
        }
        const config = Config_1.Config.getSync();
        const configUrl = config.ewizard && config.ewizard.url || 'viseven';
        const dependenciesList = this.unavailableDependencies.join('\n');
        throw new WizError_1.WizError('LIST_OF_UNAVAILABLE_DEPENDENCIES', dependenciesList, configUrl);
    }
    isNotEmptyUpdatedDependenciesList() {
        return !!this.updatedDependencies.length;
    }
    getUpdatedInformation() {
        if (this.isNotEmptyUpdatedDependenciesList()) {
            const message = this.updatedDependencies.map(dependency => dependency.message).join('\n');
            return I18n_1.default.info('UPDATED_DEPENDENCIES', message);
        }
        return I18n_1.default.info('NO_NEW_VERSIONS');
    }
}
exports.default = DependencyUpdater;
//# sourceMappingURL=index.js.map