const fs = require('fs')
const path = require('path')
const fse = require('fs-extra')

const isBinary = require('isbinaryfile')

async function generate(dir, files, base = '', rootOptions = {}) {
  const glob = require('glob')

  glob.sync('**/*', {
    cwd: dir,
    nodir: true
  }).forEach(rawPath => {
    const sourcePath = path.resolve(dir, rawPath)
    const filename = path.join(base, rawPath)

    if (isBinary.sync(sourcePath)) {
      files[filename] = fs.readFileSync(sourcePath) // return buffer
    } else {
      let content = fs.readFileSync(sourcePath, 'utf-8')
      if (path.basename(filename) === 'manifest.json') {
        content = content.replace('{{name}}', rootOptions.projectName || '')
      }
      if (filename.charAt(0) === '_' && filename.charAt(1) !== '_') {
        files[`.${filename.slice(1)}`] = content
      } else if (filename.charAt(0) === '_' && filename.charAt(1) === '_') {
        files[`${filename.slice(1)}`] = content
      } else {
        files[filename] = content
      }
    }
  })
}

module.exports = (api, options, rootOptions) => {
  const templateWithSass = [
    'dcloudio/hello-uniapp',
    'dcloudio/uni-template-news'
  ]
  api.extendPackage(pkg => {
    return {
      dependencies: {
        'regenerator-runtime': '^0.12.1',// 锁定版本,避免高版本在小程序中出错
        '@dcloudio/uni-helper-json': '*'
      },
      devDependencies: {
        "@babel/runtime": "~7.17.9",// 临时指定版本,7.13.x 会报错
        'postcss-comment': '^2.0.0',
        '@dcloudio/types': '^3.0.4',
        'miniprogram-api-typings': '*',
        'mini-types': '*'
      },
      resolutions: {
        "@babel/runtime": "~7.17.9"
      }
    }
  })
  if (options.template === 'default-ts') { // 启用 typescript
    api.extendPackage(pkg => {
      return {
        dependencies: {
          'vue-class-component': '^6.3.2',
          'vue-property-decorator': '^8.0.0'
        },
        devDependencies: {
          '@babel/plugin-syntax-typescript': '^7.2.0',
          '@vue/cli-plugin-typescript': '~4.5.11',
          'typescript': api.hasPlugin('eslint') ? '~3.1.1' : '^3.0.0'
        }
      }
    })
  } else if (templateWithSass.includes(options.template)) {
    api.extendPackage(pkg => {
      return {
        devDependencies: {
          'sass': '^1.49.8',
          'sass-loader': '^8.0.2'
        }
      }
    })
  }

  api.render(async function (files) {
    Object.keys(files).forEach(name => {
      delete files[name]
    })

    const template = options.repo || options.template

    const base = 'src'
    await generate(path.resolve(__dirname, './template/common'), files)
    if (template === 'default') {
      await generate(path.resolve(__dirname, './template/default'), files, base, rootOptions)
    } else if (template === 'default-ts') {
      await generate(path.resolve(__dirname, './template/common-ts'), files)
      await generate(path.resolve(__dirname, './template/default-ts'), files, base, rootOptions)

      // default-ts 模板删除 jsconfig.json
      process.nextTick(() => {
        const folderPath = path.resolve(process.cwd(),rootOptions.projectName)
        const jsconfigPath = path.resolve(folderPath,'./jsconfig.json')
        const tsconfigPath = path.resolve(folderPath,'./tsconfig.json')

        if(fs.existsSync(jsconfigPath) && fs.existsSync(tsconfigPath)){
          fs.unlinkSync(jsconfigPath)
        }
      })
    } else {
      const ora = require('ora')
      const home = require('user-home')
      const download = require('download-git-repo')

      const spinner = ora('模板下载中...')
      spinner.start()

      const tmp = path.join(home, '.uni-app/templates', template.replace(/[/:]/g, '-'), 'src')

      if (fs.existsSync(tmp)) {
        try {
          require('rimraf').sync(tmp)
        } catch (e) {
          console.error(e)
        }
      }

      await new Promise((resolve, reject) => {
        download(template, tmp, err => {
          spinner.stop()
          if (err) {
            return reject(err)
          }
          resolve()
        })
      })

      // 合并模板依赖
      const jsonPath = path.join(tmp, './package.json')
      if (fs.existsSync(jsonPath)) {
        try {
          const json = fs.readFileSync(jsonPath, { encoding: 'utf-8' })
          content = JSON.parse(json)
          api.extendPackage(pkg => {
            return {
              dependencies: Object.assign({}, content.dependencies),
              devDependencies: Object.assign({}, content.devDependencies)
            }
          })
        } catch (error) {
          console.warn('package.json merge failed')
        }
      }

      const dirNames = ['cloudfunctions-aliyun', 'cloudfunctions-tcb']
      dirNames.forEach(dirName => {
        const dirPath = path.join(tmp, './', dirName)
        if (fs.existsSync(dirPath)) {
          fse.moveSync(dirPath, path.join(tmp, '../', dirName), {
            overwrite: true
          })
        }
      })

      await generate(path.join(tmp, '../'), files, path.join(base, '../'))
    }
  })
}