const {src, dest, task, series, parallel} = require('gulp')
const webpack = require('webpack-stream')
const less = require('gulp-less')
const autoprefix = require('gulp-autoprefixer')
const uglify = require('gulp-uglify')
const minifyCSS = require('gulp-csso')
const zip = require('gulp-zip')
const rename = require('gulp-rename')
const clean = require('gulp-clean')
const path = require('path')
const execSync = require('child_process').execSync
const fs = require('fs')
const resolve = (name) => path.resolve(__dirname, name)
const cssPath = './templates/assets/css'
const jsPath = './templates/assets/js'
const distPath = './dist'
const devModel = process.env.npm_config_devel
const version = process.env.npm_config_tag

if (devModel) {
  console.log('> 开发模式')
}
version && console.log(`> 发布版本:${version}`)

task('clean', () => {
  return src([cssPath, jsPath, distPath], {
    read: false,
    allowEmpty: true,
  }).pipe(
    clean({
      force: true,
    })
  )
})

task('version', (done) => {
  if (version == null) {
    console.log('[Version] No \'--tag\' parameters are specified')
    done()
    return
  }
  const themePath = 'theme.yaml'
  const packagePath = 'package.json'
  const themeData = fs.readFileSync(themePath, 'utf8')
    .replace(/^(\s+version:)\s+[^\s]+$/m, '$1 ' + version)
  fs.writeFileSync(themePath, themeData)
  let packageData = fs.readFileSync(packagePath, 'utf8')
    .replace(/"version":\s*"[^"]+"/, `"version": "${version}"`)
  fs.writeFileSync(packagePath, packageData)
  done()
})

task('css', () => {
  const ignoreFiles = [].map((file) => `./src/css/${file}.less`)

  let gw = src('./src/css/**/*.less', {
    ignore: ignoreFiles,
  })
    .pipe(less())
    .pipe(
      autoprefix({
        overrideBrowserslist: ['> 2%', 'last 2 versions', 'not ie 6-9'],
        cascade: false,
      })
    )
  if (!devModel) {
    gw = gw.pipe(minifyCSS())
  }

  return gw.pipe(
    rename({
      suffix: '.min',
    })
  ).pipe(dest(cssPath))
})

task('js', () => {
  const readFile = (prefix, dir, ignoreFiles) => {
    let result = {}
    let files = fs.readdirSync(dir, 'utf-8')
    files.forEach((file) => {
      let filePath = path.join(dir, file)
      let states = fs.statSync(filePath)
      if (states.isDirectory()) {
        Object.assign(result, readFile(path.join(prefix, file), filePath, ignoreFiles))
      } else if (ignoreFiles.length
        ? /\.js$/.test(file) && !ignoreFiles.includes(path.join(prefix, file))
        : /\.js$/.test(file)) {
        const fileName = file.replace(/.js$/, '')
        result[path.join(prefix, fileName)] = resolve(filePath)
      }
    })
    return result
  }
  const getEntryData = () => {
    return readFile('', './src/js', [])
  }

  return webpack({
    mode: devModel ? 'development' : 'production',
    entry: getEntryData(),
    module: {
      rules: [
        {
          test: /\.js$/,
          loader: 'babel-loader',
          include: resolve('source'),
          exclude: resolve('node_modules'),
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime'],
          },
        },
      ],
    },
    stats: 'errors-only',
    output: {
      filename: '[name].min.js',
    },
  })
    .pipe(uglify())
    .pipe(dest(jsPath))
})

task('zip', () => {
  const target = ['./templates/**', './*.yaml', 'README.md', 'LICENSE']
  return src(target, {base: '.'})
    .pipe(zip('halo-theme-dream2.0-plus.zip'))
    .pipe(dest(distPath))
})

task('publish', (done) => {
  try {
    // 切换到项目根目录
    process.chdir(path.resolve(__dirname, '..'))

    // 需要将tag标签内容置为 latest
    process.env.npm_config_tag = 'latest'
    console.log(execSync('npm publish').toString())
    done()
  } catch (error) {
    console.error('发布失败:', error.message)
    done(error)
  }
})

// 默认模式
task('default', series('clean', parallel('css', 'js'), 'zip'))

// release模式,需要使用--tag参数指定版本号
task('release', series('clean', 'version', parallel('css', 'js'), 'zip'))

// push模式,需要使用--tag参数指定版本号
task('push', series('clean', 'version', parallel('css', 'js'), 'zip', 'publish'))