text: /*---------------------------------------------------------
   * Copyright (C) upcwangying.com. All rights reserved.
   *--------------------------------------------------------*/
  'use strict'
  
  const Generator = require('yeoman-generator')
  const yosay = require('yosay')
  const camelCase = require('camelcase')
  
  const path = require('path')
  const validator = require('../libs/validators')
  const chalk = require('chalk')
  
  module.exports = class extends Generator {
    constructor(args, opts) {
      super(args, opts)
      this.option('type', { type: String })
      this.option('name', { type: String })
      this.option('description', { type: String })
      this.option('author', { type: String })
      this.option('license', { type: String })
  
      this.extensionConfig = Object.create(null)
      this.extensionConfig.installDependencies = false
    }
  
    initializing() {
      // Welcome
      this.log(yosay('Welcome to the see generator!'))
    }
  
    prompting() {
      const generator = this
      const prompts = {
        // 1. Ask for type.
        askForType: () => {
          let extensionType = generator.options['type']
          if (extensionType) {
            let extensionTypes = ['plugin', 'loader']
            if (extensionTypes.indexOf(extensionType) !== -1) {
              generator.extensionConfig.type = `see-${extensionType}`
            } else {
              generator.log(
                'Invalid extension type: ' +
                  extensionType +
                  '. Possible types are :' +
                  extensionTypes.join(', '),
              )
            }
            return Promise.resolve()
          }
  
          return generator
            .prompt({
              type: 'list',
              name: 'type',
              message: 'What type of project do you want to create?',
              choices: [
                {
                  name: 'New Plugin',
                  value: 'see-plugin',
                },
                {
                  name: 'New Loader',
                  value: 'see-loader',
                },
              ],
            })
            .then(typeAnswer => {
              generator.extensionConfig.type = typeAnswer.type
            })
        },
  
        // 2. Ask for name.
        askForProjectName: () => {
          const name = generator.options['name']
          if (name) {
            generator.extensionConfig.name = name
            generator.extensionConfig.displayName = camelCase(name, { pascalCase: true })
            return Promise.resolve()
          }
  
          return generator
            .prompt({
              type: 'input',
              name: 'name',
              message: "What's the name of your project?",
              default: generator.extensionConfig.name,
              validate: validator.isPluginId,
            })
            .then(displayNameAnswer => {
              generator.extensionConfig.name = displayNameAnswer.name
              generator.extensionConfig.displayName = camelCase(displayNameAnswer.name, {
                pascalCase: true,
              })
            })
        },
  
        // 3. Ask for project description.
        askForProjectDesc: () => {
          const description = generator.options['description']
          if (description) {
            generator.extensionConfig.description = description
            return Promise.resolve()
          }
  
          return generator
            .prompt({
              type: 'input',
              name: 'description',
              message: "What's the description of your project?",
              default: 'A see project generated by see generator.',
            })
            .then(nameAnswer => {
              generator.extensionConfig.description = nameAnswer.description
            })
        },
  
        // 4. Ask for project author
        askForProjectAuthor: () => {
          const author = generator.options['author']
          if (author) {
            generator.extensionConfig.author = author
            return Promise.resolve()
          }
  
          return generator
            .prompt({
              type: 'input',
              name: 'author',
              message: "What's the author of your project?",
            })
            .then(descriptionAnswer => {
              generator.extensionConfig.author = descriptionAnswer.author
            })
        },
  
        // 5. Ask for project license
        askForProjectLicense: () => {
          const license = generator.options['license']
          if (license) {
            generator.extensionConfig.license = license
            return Promise.resolve()
          }
  
          return generator
            .prompt({
              type: 'input',
              name: 'license',
              message: "What's the license of your project?",
              default: 'MIT',
            })
            .then(descriptionAnswer => {
              generator.extensionConfig.license = descriptionAnswer.license
            })
        },
  
        // 6. Ask for project license
        askForPackageManager: () => {
          if (['see-loader', 'see-plugin'].indexOf(generator.extensionConfig.type) === -1) {
            return Promise.resolve()
          }
  
          generator.extensionConfig.pkgManager = 'npm'
          return generator
            .prompt({
              type: 'list',
              name: 'pkgManager',
              message: 'Which package manager to use?',
              choices: [
                {
                  name: 'npm',
                  value: 'npm',
                },
                {
                  name: 'yarn',
                  value: 'yarn',
                },
              ],
            })
            .then(pckgManagerAnswer => {
              generator.extensionConfig.pkgManager = pckgManagerAnswer.pkgManager
            })
        },
  
        // 7. Ask for git
        askForGit: () => {
          return generator
            .prompt({
              type: 'confirm',
              name: 'gitInit',
              message: 'Initialize a git repository?',
              default: true,
            })
            .then(gitAnswer => {
              generator.extensionConfig.gitInit = gitAnswer.gitInit
            })
        },
  
        // 8. Ask for git repo url
        askForGitRepoUrl: () => {
          generator.extensionConfig.gitRepo = 'https://github.com/your-name/your-repo-name'
          if (!generator.extensionConfig.gitInit) {
            return Promise.resolve()
          }
  
          return generator
            .prompt({
              type: 'confirm',
              name: 'gitRepo',
              message: "What's the url of your repository?",
            })
            .then(gitAnswer => {
              generator.extensionConfig.gitRepo = gitAnswer.gitRepo
            })
        },
      }
  
      // run all prompts in sequence. Results can be ignored.
      let result = Promise.resolve()
      for (let taskName in prompts) {
        let prompt = prompts[taskName]
        result = result.then(_ => {
          return new Promise((s, r) => {
            setTimeout(_ => prompt().then(s, r), 0) // set timeout is required, otherwise node hangs
          })
        })
      }
      return result
    }
    // Write files
    writing() {
      this.sourceRoot(path.join(__dirname, './templates/' + this.extensionConfig.type))
  
      switch (this.extensionConfig.type) {
        case 'see-loader':
          this._writingSeeLoader()
          break
        case 'see-plugin':
          this._writingSeePlugin()
          break
        default:
          //unknown project type
          break
      }
    }
  
    // Write see loader
    _writingSeeLoader() {
      const context = this.extensionConfig
  
      this.fs.copy(this.sourceRoot() + '/docs', context.name + '/docs')
      this.fs.copy(this.sourceRoot() + '/samples', context.name + '/samples')
      this.fs.copy(this.sourceRoot() + '/tests', context.name + '/tests')
      this.fs.copy(this.sourceRoot() + '/src/cjs.js', context.name + '/src/cjs.js')
      this.fs.copyTpl(this.sourceRoot() + '/src/index.js', context.name + '/src/index.js', context)
  
      if (context.gitInit) {
        this.fs.copy(this.sourceRoot() + '/.gitignore', context.name + '/.gitignore')
      }
  
      this.fs.copy(this.sourceRoot() + '/.all-contributorsrc', context.name + '/.all-contributorsrc')
      this.fs.copy(this.sourceRoot() + '/.editorconfig', context.name + '/.editorconfig')
      this.fs.copy(this.sourceRoot() + '/eslintignore', context.name + '/.eslintignore')
      this.fs.copy(this.sourceRoot() + '/eslintrc', context.name + '/.eslintrc')
      this.fs.copy(this.sourceRoot() + '/prettierignore', context.name + '/.prettierignore')
      this.fs.copy(this.sourceRoot() + '/prettierrc', context.name + '/.prettierrc')
      this.fs.copy(this.sourceRoot() + '/.yarnrc', context.name + '/.yarnrc')
      this.fs.copyTpl(this.sourceRoot() + '/CHANGELOG.md', context.name + '/CHANGELOG.md', context)
      this.fs.copy(this.sourceRoot() + '/CONTRIBUTING.md', context.name + '/CONTRIBUTING.md')
      this.fs.copy(this.sourceRoot() + '/CONTRIBUTORS.md', context.name + '/CONTRIBUTORS.md')
      this.fs.copy(this.sourceRoot() + '/jest.config.js', context.name + '/jest.config.js')
      this.fs.copy(this.sourceRoot() + '/jest.setup.js', context.name + '/jest.setup.js')
      this.fs.copyTpl(this.sourceRoot() + '/LICENSE.md', context.name + '/LICENSE.md', context)
      this.fs.copyTpl(this.sourceRoot() + '/package.json', context.name + '/package.json', context)
      this.fs.copyTpl(this.sourceRoot() + '/README.md', context.name + '/README.md', context)
  
      this.extensionConfig.installDependencies = true
    }
  
    // Write see plugin
    _writingSeePlugin() {
      const context = this.extensionConfig
  
      this.fs.copy(this.sourceRoot() + '/docs', context.name + '/docs')
      this.fs.copy(this.sourceRoot() + '/samples', context.name + '/samples')
      this.fs.copy(this.sourceRoot() + '/tests', context.name + '/tests')
      this.fs.copy(this.sourceRoot() + '/src/cjs.js', context.name + '/src/cjs.js')
      this.fs.copyTpl(this.sourceRoot() + '/src/index.js', context.name + '/src/index.js', context)
  
      if (context.gitInit) {
        this.fs.copy(this.sourceRoot() + '/.gitignore', context.name + '/.gitignore')
      }
  
      this.fs.copy(this.sourceRoot() + '/.all-contributorsrc', context.name + '/.all-contributorsrc')
      this.fs.copy(this.sourceRoot() + '/.editorconfig', context.name + '/.editorconfig')
      this.fs.copy(this.sourceRoot() + '/eslintignore', context.name + '/.eslintignore')
      this.fs.copy(this.sourceRoot() + '/eslintrc', context.name + '/.eslintrc')
      this.fs.copy(this.sourceRoot() + '/prettierignore', context.name + '/.prettierignore')
      this.fs.copy(this.sourceRoot() + '/prettierrc', context.name + '/.prettierrc')
      this.fs.copy(this.sourceRoot() + '/.yarnrc', context.name + '/.yarnrc')
      this.fs.copyTpl(this.sourceRoot() + '/CHANGELOG.md', context.name + '/CHANGELOG.md', context)
      this.fs.copy(this.sourceRoot() + '/CONTRIBUTING.md', context.name + '/CONTRIBUTING.md')
      this.fs.copy(this.sourceRoot() + '/CONTRIBUTORS.md', context.name + '/CONTRIBUTORS.md')
      this.fs.copy(this.sourceRoot() + '/jest.config.js', context.name + '/jest.config.js')
      this.fs.copy(this.sourceRoot() + '/jest.setup.js', context.name + '/jest.setup.js')
      this.fs.copyTpl(this.sourceRoot() + '/LICENSE.md', context.name + '/LICENSE.md', context)
      this.fs.copyTpl(this.sourceRoot() + '/package.json', context.name + '/package.json', context)
      this.fs.copyTpl(this.sourceRoot() + '/README.md', context.name + '/README.md', context)
  
      this.extensionConfig.installDependencies = true
    }
  
    // Installation
    install() {
      process.chdir(this.extensionConfig.name)
  
      if (this.extensionConfig.installDependencies) {
        this.installDependencies({
          yarn: this.extensionConfig.pkgManager === 'yarn',
          npm: this.extensionConfig.pkgManager === 'npm',
          bower: false,
        })
      }
    }
  
    // End
    end() {
      // Git init
      if (this.extensionConfig.gitInit) {
        this.spawnCommand('git', ['init', '--quiet'])
      }
  
      this.log('')
      this.log('Your project ' + this.extensionConfig.name + ' has been created!')
      this.log('')
    }
  }
  