'use strict';

const Generator = require('yeoman-generator');
const chalk = require('chalk');
const yosay = require('yosay');
const { mergePackageKey, mergeIgnoreFile, packageNameFromPluginName } = require('./utils');

module.exports = class extends Generator {

	constructor(args, opts) {
		super(args, opts);

		this.option('silent');
		this.option('update');
	}

	async prompting() {
		this.log(yosay(`Welcome to the fine ${chalk.red('Joplin Plugin')} generator!`));

		if (this.options.update && !this.options.silent) {
			const answers = await this.prompt([
				{
					type: 'confirm',
					name: 'proceed',
					message: [
						'Updating will overwrite the config-related files. It will not change the',
						'  content of /src or README.md. If you have made any changes to some of the',
						'  config files make sure your code is under version control so that you can',
						'  inspect the diff and re-apply your changes if needed. Do you want to proceed?',
					].join('\n'),
				},
			]);

			if (!answers.proceed) {
				this.log('');
				this.log('Operation was cancelled and no changes was made');
				process.exit(0);
			}
		}

		const prompts = [
			{
				type: 'input',
				name: 'pluginId',
				message: 'Plugin ID\n  Must be a globally unique ID such as "com.example.MyPlugin" or a UUID:',
			},
			{
				type: 'input',
				name: 'pluginName',
				message: 'Plugin name\n  User-friendly string which will be displayed in UI:',
			},
			{
				type: 'input',
				name: 'pluginDescription',
				message: 'Plugin description:',
			},
			{
				type: 'input',
				name: 'pluginAuthor',
				message: 'Author:',
			},
			{
				type: 'input',
				name: 'pluginRepositoryUrl',
				message: 'Repository URL:',
			},
			{
				type: 'input',
				name: 'pluginHomepageUrl',
				message: 'Homepage URL:',
			},
		];

		if (this.options.update) {
			const props = {};
			for (const prompt of prompts) {
				props[prompt.name] = '';
			}
			props.packageName = '';

			this.props = props;
		} else {
			const initialProps = await this.prompt(prompts);

			const defaultPackageName = packageNameFromPluginName(initialProps.pluginName);

			const derivedProps = await this.prompt([
				{
					type: 'input',
					name: 'packageName',
					message: `The npm package will be named: "${defaultPackageName}"\n  Press ENTER to keep this default, or type a name to change it:`,
				},
			]);

			if (!derivedProps.packageName) derivedProps.packageName = defaultPackageName;

			this.props = { ...initialProps, ...derivedProps };
		}
	}

	writing() {
		// Due to WONTFIX bug in npm, which treats .gitignore and pakage.json in a special way,
		// we need to give them a different name in the templates dir and then rename them
		// when installing.
		// https://github.com/npm/npm/issues/3763

		const files = [
			'.gitignore_TEMPLATE',
			'.npmignore_TEMPLATE',
			'GENERATOR_DOC.md',
			'package_TEMPLATE.json',
			'tsconfig.json',
			'webpack.config.js',
			'plugin.config.json',
		];

		const noUpdateFiles = [
			'src/index.ts',
			'src/manifest.json',
			'README.md',
		];

		const allFiles = files.concat(noUpdateFiles);

		for (const file of allFiles) {
			if (this.options.update && noUpdateFiles.includes(file)) continue;

			const destFile = file.replace(/_TEMPLATE/, '');
			const destFilePath = this.destinationPath(destFile);

			if (this.options.update && destFile === 'package.json' && this.fs.exists(destFilePath)) {
				const destContent = this.fs.readJSON(destFilePath);

				this.fs.copy(
					this.templatePath(file),
					destFilePath, {
						process: (sourceBuffer) => {
							const sourceContent = JSON.parse(sourceBuffer.toString());
							const newContent = mergePackageKey(null, sourceContent, destContent);
							return JSON.stringify(newContent, null, 2);
						},
					},
				);
			} else if (this.options.update && destFile === 'plugin.config.json' && this.fs.exists(destFilePath)) {
				// Keep existing content for now. Maybe later we could merge the configs.
			} else if (this.options.update && (destFile === '.gitignore' || destFile === '.npmignore') && this.fs.exists(destFilePath)) {
				const destContent = this.fs.read(destFilePath);

				this.fs.copy(
					this.templatePath(file),
					destFilePath, {
						process: (sourceBuffer) => {
							return mergeIgnoreFile(sourceBuffer.toString(), destContent);
						},
					},
				);
			} else if (this.options.update) {
				this.fs.copy(
					this.templatePath(file),
					destFilePath, {
						process: (sourceBuffer) => {
							return sourceBuffer.toString();
						},
					},
				);
			} else {
				this.fs.copyTpl(
					this.templatePath(file),
					destFilePath,
					this.props,
				);
			}
		}

		this.fs.copy(
			this.templatePath('api'),
			this.destinationPath('api'),
		);
	}

};
