"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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = require("chalk");
const child_process_1 = require("child_process");
const fs = require("fs");
const node_fetch_1 = require("node-fetch");
const ora = require("ora");
const path = require("path");
const tar = require("tar");
const errors_1 = require("../../server/errors");
const util_1 = require("../../server/util");
const writer_1 = require("../writer");
const launchpadUrl = 'https://mixercc.azureedge.net/launchpad/interactive-launchpad_1.0.tar.gz';
/**
 * installRepo clones and installs the Interactive launchpad.
 */
function installRepo(dir, npmPath) {
    return __awaiter(this, void 0, void 0, function* () {
        const res = yield node_fetch_1.default(launchpadUrl);
        if (res.status !== 200) {
            throw new errors_1.UnexpectedHttpError(res, yield res.text());
        }
        yield new Promise((resolve, reject) => {
            res.body
                .pipe(tar.extract({ cwd: dir }))
                .on('error', reject)
                .on('end', resolve);
        });
        yield util_1.awaitChildProcess(child_process_1.spawn(npmPath, ['install'], { cwd: dir }));
    });
}
/**
 * getDetails prompts the user for and loads overrides for the package.json file.
 */
function getDetails(bundleName) {
    return __awaiter(this, void 0, void 0, function* () {
        const name = yield writer_1.default.ask('Bundle name:', bundleName, n => {
            if (!/^[a-z0-9\-]{2,60}$/i.test(n)) {
                return 'The bundle name must be alphanumeric with dashes';
            }
            return undefined;
        });
        const description = yield writer_1.default.ask('Bundle description:');
        const keywords = yield writer_1.default.ask('Keywords (separated by commas):');
        const license = yield writer_1.default.ask('License:', 'MIT');
        return {
            name,
            description: description ? description : undefined,
            version: '0.1.0',
            author: undefined,
            keywords: keywords ? keywords.split(',').map(kw => kw.toLowerCase().trim()) : [],
            license,
        };
    });
}
function applyDetails(dir, details) {
    return __awaiter(this, void 0, void 0, function* () {
        const packageJsonPath = path.join(dir, 'package.json');
        const source = yield util_1.readFile(packageJsonPath);
        const updated = JSON.stringify(Object.assign({}, JSON.parse(source), details), null, 2);
        yield util_1.writeFile(packageJsonPath, updated);
    });
}
function default_1(options) {
    return __awaiter(this, void 0, void 0, function* () {
        const dir = options.dir
            ? path.resolve(options.dir)
            : path.join(process.cwd(), options.projectName);
        if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir);
        }
        let installed = false;
        let spinner;
        const [details] = yield Promise.all([
            getDetails(options.projectName).then(d => {
                if (!installed) {
                    spinner = ora('Installing dependencies...').start();
                }
                return d;
            }),
            installRepo(dir, options.npm).then(() => {
                installed = true;
            }),
        ]);
        yield applyDetails(dir, details);
        const message = `Project created in ${chalk_1.default.green(path.relative(process.cwd(), dir))}`;
        if (spinner) {
            spinner.succeed(message);
        }
        else {
            writer_1.default.write(message);
        }
    });
}
exports.default = default_1;
