"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const files_1 = require("@iotize/common/files");
const command_1 = require("@oclif/command");
const fs_1 = __importStar(require("fs"));
const fs_extra_1 = require("fs-extra");
const path_1 = require("path");
const lib_1 = require("../../lib");
const shell_1 = require("../../lib/shell");
const package_manager_1 = require("../../lib/utility/package-manager");
function showInfo(v) {
    console.log(v);
}
let generationInProgress = false;
function setupWatchConfigChangeRegenerateApp(filepath) {
    if (fs_1.existsSync(filepath)) {
        fs_1.watchFile(filepath, async (curr, prev) => {
            try {
                if (!generationInProgress) {
                    generationInProgress = true;
                    await lib_1.execIonicToolkitSchematics('app-config', {
                        tapConfig: filepath,
                        rebuild: true
                    });
                    await lib_1.execIonicToolkitSchematics('generate', {})
                        .catch(err => {
                        // console.warn('Generation error', err)
                    })
                        .then(() => {
                        setTimeout(() => {
                            generationInProgress = false;
                        }, 2000);
                    });
                }
            }
            catch (err) {
                generationInProgress = false;
                console.warn(err);
            }
        });
    }
}
exports.setupWatchConfigChangeRegenerateApp = setupWatchConfigChangeRegenerateApp;
function ngServe(options = {}, localVersion = true) {
    const args = ['serve', '--port', (options.port || 4210).toString()];
    if (options.open) {
        args.push('--open');
    }
    if (options.args) {
        args.push(options.args);
    }
    return shell_1.shell.execSpawn(localVersion ? path_1.resolve(`node_modules/.bin/ng`) : 'ng', args);
}
function resolveTemplate(template) {
    const templateFileName = path_1.resolve(__dirname, '..', '..', '..', 'assets', 'templates', `${template}.iotz`);
    if (!fs_1.existsSync(templateFileName)) {
        console.warn(`Cannot find file ${templateFileName}`);
        throw new Error(`Template name "${template}" does not exist`);
    }
    return templateFileName;
}
function isDirectoryEmpty(directoryName) {
    return fs_1.default.promises.readdir(directoryName).then(files => {
        return files.length === 0;
    });
}
class StartCommand extends command_1.Command {
    async run() {
        const parsedInput = this.parse(StartCommand);
        const appPath = parsedInput.args.appPath;
        const options = parsedInput.flags;
        if (!options.template && !options.tapConfig && !options.config) {
            this.error(new Error(`At least one of the following flag is exepected: --template, --tapConfig, --config`));
        }
        // const testSchema: AppJsonSchema = {} as any;
        showInfo(`Working directory: ${process.cwd()}`);
        const absolutePath = path_1.resolve(process.cwd(), appPath);
        const tapConfig = options.tapConfig
            ? path_1.resolve(process.cwd(), options.tapConfig)
            : options.template ? resolveTemplate(options.template) : undefined;
        const config = options.config
            ? path_1.resolve(options.config)
            : undefined;
        const parentDir = path_1.dirname(absolutePath);
        const baseName = path_1.basename(absolutePath);
        const appName = options.name || baseName;
        if (!fs_1.existsSync(absolutePath)) {
            fs_extra_1.mkdirpSync(absolutePath);
        }
        else {
            if (!files_1.isDirectory(absolutePath)) {
                throw new Error(`"${absolutePath}" must be a directory`);
            }
            if (!await isDirectoryEmpty(absolutePath)) {
                this.warn(`${absolutePath} directory is not empty. If you encounter errors during build, try to clean output directory and rerun generation.`);
            }
        }
        process.chdir(absolutePath);
        showInfo(`Working directory: ${process.cwd()}`);
        await lib_1.execIonicToolkitSchematics('new-app', {
            overwrite: true,
            name: appName,
            config: config,
            tapConfig,
            dryRun: options.dryRun,
            skipInstall: options.skipInstall
        }, {
            dryRun: options.dryRun
        });
        if (!options.skipInstall) {
            await package_manager_1.packageManager.installAll({
                cwd: absolutePath
            });
        }
        if (options.serve) {
            if (options.watch) {
                if (!options.tapConfig) {
                    throw new Error(`'tapConfig' option must be used when using 'watch' option`);
                }
                setupWatchConfigChangeRegenerateApp(options.tapConfig);
            }
            await ngServe({
                port: options.port,
                args: options.ngOptions
            });
        }
        else {
            showInfo(`New application created in "${process.cwd()}"`);
            showInfo(`Go to "${absolutePath}" directory and run your app:`);
            showInfo(`  - "npm run android" for Android platform`);
            showInfo(`  - "npm run ios" for iOS platform`);
            showInfo(`  - "npm run webapp" for browser platform`);
        }
    }
}
exports.default = StartCommand;
StartCommand.description = 'Create a new application project or regenerate an existing one';
StartCommand.examples = [
    `start ./app-dir --tapConfig ./SensorDemo.iotz`,
    `start ./app-dir --template SensorDemo`
];
StartCommand.flags = {
    help: command_1.flags.help({ char: 'h' }),
    tapConfig: command_1.flags.string({
        description: 'IoTize Studio configuration file (.iotz)',
        exclusive: ['template']
    }),
    template: command_1.flags.string({
        description: 'Generate application from template configuration file. Usefull for demos',
        options: [
            'SensorDemo'
        ],
        exclusive: ['tapConfig']
    }),
    config: command_1.flags.string({
        description: 'Generated app configuration file (.json)'
    }),
    name: command_1.flags.string({
        description: 'Application name'
    }),
    serve: command_1.flags.boolean({
        description: 'Serve application (Angular CLI must be installed)'
    }),
    watch: command_1.flags.boolean({
        description: 'Regenerate application when configuration file is updated'
    }),
    port: command_1.flags.integer({
        description: 'Port used to serve application (only with --serve option)',
        dependsOn: ['serve']
    }),
    ngOptions: command_1.flags.string({
        description: 'Additional ng options (for angular cli)',
        dependsOn: ['serve']
    }),
    dryRun: command_1.flags.boolean({}),
    skipInstall: command_1.flags.boolean({
        description: 'Skip dependency packages installation'
    }),
};
StartCommand.args = [
    {
        name: 'appPath',
        required: true
    }
];
//# sourceMappingURL=start.js.map