"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
const command_1 = require("@oclif/command");
const commit_1 = tslib_1.__importDefault(require("./commit"));
const pull_1 = tslib_1.__importDefault(require("./pull"));
const push_1 = tslib_1.__importDefault(require("./push"));
const base_1 = tslib_1.__importDefault(require("../base"));
const utils_1 = require("../utils");
const git_1 = require("../utils/git");
const logger_1 = tslib_1.__importDefault(require("../utils/logger"));
const collection_1 = require("../utils/collection");
const constants_1 = require("../constants");
const assets_1 = require("../utils/assets");
class Sync extends base_1.default {
    async copyFilesFromTutureBranch() {
        await git_1.git.checkout(constants_1.TUTURE_BRANCH);
        // COMPAT: copy files from project root for older alpha versions.
        if (fs_extra_1.default.existsSync(constants_1.COLLECTION_PATH)) {
            fs_extra_1.default.copySync(constants_1.COLLECTION_PATH, collection_1.collectionPath);
        }
        if (fs_extra_1.default.existsSync(constants_1.ASSETS_JSON_PATH)) {
            fs_extra_1.default.copySync(constants_1.ASSETS_JSON_PATH, assets_1.assetsTablePath);
        }
        if (fs_extra_1.default.existsSync(collection_1.collectionVcsPath)) {
            fs_extra_1.default.copySync(collection_1.collectionVcsPath, collection_1.collectionPath);
        }
        collection_1.saveCheckpoint();
    }
    async pullFromRemotes(remotes) {
        await Promise.all(remotes.map(({ name }) => new Promise((resolve) => {
            pull_1.default.run(['-r', name.trim()]).then(() => resolve());
        })));
    }
    async pushToRemotes(remotes) {
        await Promise.all(remotes.map(({ name }) => new Promise((resolve) => {
            push_1.default.run(['-r', name.trim()]).then(() => resolve());
        })));
    }
    async run() {
        const { flags } = this.parse(Sync);
        this.userConfig = Object.assign(this.userConfig, flags);
        try {
            await utils_1.checkInitStatus();
        }
        catch (err) {
            logger_1.default.log('error', err.message);
            this.exit(constants_1.EXIT_CODE.NOT_INIT);
        }
        const { conflicted, staged } = await git_1.git.status();
        if (conflicted.length > 0) {
            logger_1.default.log('error', `You still have unresolved conflict file(s): ${conflicted}`);
            this.exit(constants_1.EXIT_CODE.CONFLICT);
        }
        if (flags.continue) {
            if (staged.length === 0) {
                logger_1.default.log('error', `You have not staged any file. Aborting.`);
                this.exit(constants_1.EXIT_CODE.NO_STAGE);
            }
            await git_1.git.commit(`Resolve conflict during sync (${new Date()})`);
            await this.copyFilesFromTutureBranch();
            const collection = collection_1.loadCollection();
            if (flags.configureRemotes ||
                !collection.remotes ||
                collection.remotes.length === 0) {
                const remotes = await git_1.git.getRemotes(true);
                if (remotes.length === 0) {
                    logger_1.default.log('error', 'Remote repository has not been configured.');
                    this.exit(constants_1.EXIT_CODE.NO_REMOTE);
                }
                else {
                    collection.remotes = await git_1.selectRemotes(remotes, collection.remotes);
                    collection_1.saveCollection(collection);
                }
            }
            if (!flags.noPush) {
                await this.pushToRemotes(collection.remotes);
            }
            await git_1.git.checkout('master');
            logger_1.default.log('success', 'Synchronization complete!');
            this.exit(0);
        }
        if (!fs_extra_1.default.existsSync(collection_1.collectionPath)) {
            await collection_1.initializeTutureBranch();
            await git_1.git.checkout(constants_1.TUTURE_BRANCH);
            // COMPAT: check both project root and vcs root.
            if (!fs_extra_1.default.existsSync(constants_1.COLLECTION_PATH) &&
                !fs_extra_1.default.existsSync(collection_1.collectionVcsPath)) {
                logger_1.default.log('error', `Cannot load collection data. Please run ${chalk_1.default.bold('tuture init')} to initialize.`);
                this.exit(constants_1.EXIT_CODE.NOT_INIT);
            }
            await this.copyFilesFromTutureBranch();
            logger_1.default.log('success', 'Workspace created from remote tuture branch!');
        }
        else {
            const collection = collection_1.loadCollection();
            if (flags.configureRemotes ||
                !collection.remotes ||
                collection.remotes.length === 0) {
                const remotes = await git_1.git.getRemotes(true);
                if (remotes.length === 0) {
                    logger_1.default.log('error', 'Remote repository has not been configured.');
                    this.exit(constants_1.EXIT_CODE.NO_REMOTE);
                }
                else {
                    collection.remotes = await git_1.selectRemotes(remotes, collection.remotes);
                    collection_1.saveCollection(collection);
                }
            }
            // Step 1: run `commit` command if something has changed.
            if (collection_1.hasCollectionChangedSinceCheckpoint()) {
                const message = flags.message || `Commit on ${new Date()}`;
                await commit_1.default.run(['-m', message]);
            }
            // Step 2: run `pull` command
            if (!flags.noPull && (await collection_1.hasRemoteTutureBranch())) {
                await this.pullFromRemotes(collection.remotes);
            }
            // Step 3: run `push` command
            if (!flags.noPush) {
                await this.pushToRemotes(collection.remotes);
            }
            await this.copyFilesFromTutureBranch();
            logger_1.default.log('success', 'Synchronization complete!');
        }
    }
}
exports.default = Sync;
Sync.description = 'Synchronize workspace with local/remote branch';
Sync.flags = {
    help: command_1.flags.help({ char: 'h' }),
    message: command_1.flags.string({
        char: 'm',
        description: 'commit message',
    }),
    noPull: command_1.flags.boolean({
        description: 'do not pull from remote',
        default: false,
    }),
    noPush: command_1.flags.boolean({
        description: 'do not push to remote',
        default: false,
    }),
    configureRemotes: command_1.flags.boolean({
        description: 'configure remotes before synchronization',
        default: false,
    }),
    continue: command_1.flags.boolean({
        description: 'continue synchronization after resolving conflicts',
        default: false,
    }),
};
