const path = require('path')
const webpack = require('webpack')
const MFS = require('memory-fs')
const clientConfig = require('./webpack.client.config')
const serverConfig = require('./webpack.server.config')
const checkPort = require('./checkPort')

process.env.NODE_ENV === 'development'
const readFile = (fs, file) => {
  try {
    return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8')
  } catch (e) {
    //
  }
}

module.exports = async function setupDevServer(app, cb) {
  let bundle, clientManifest
  let resolve

  const readyPromise = new Promise(_resolve => {
    resolve = _resolve
  })
  const ready = (...args) => {
    resolve()
    cb(...args)
  }
  const port = await checkPort()
  // 注入环境变量
  const injectEnv = require(`../config/env.dev.js`)
  injectEnv.BASE_URL = `"http://localhost:${port}"`
  clientConfig.plugins.push(
    // strip dev-only code in Vue source
    new webpack.DefinePlugin({
      'process.env': { ...injectEnv, VUE_ENV: '"client"' }
    })
  )
  serverConfig.plugins.push(
    // strip dev-only code in Vue source
    new webpack.DefinePlugin({
      'process.env': { ...injectEnv, VUE_ENV: '"server"' }
    })
  )
  process.env.__SAFE_PORT__ = port
  process.env.BASE_API_PREFIX = injectEnv.BASE_API_PREFIX

  /****** client ******/

  // modify client config to work with hot middleware
  // see https://github.com/webpack-contrib/webpack-hot-middleware#readme
  clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app]
  clientConfig.output.filename = '[name].js'
  clientConfig.plugins.push(new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin())
  // dev middleware
  const clientCompiler = webpack(clientConfig)
  const devMiddleware = require('webpack-dev-middleware')(clientCompiler, {
    publicPath: clientConfig.output.publicPath,
    noInfo: true,
    clientLogLevel: 'warning'
  })

  app.use(devMiddleware)

  clientCompiler.plugin('done', stats => {
    stats = stats.toJson()
    stats.errors.forEach(err => console.error(err))
    stats.warnings.forEach(err => console.warn(err))
    if (stats.errors.length) return

    clientManifest = JSON.parse(readFile(devMiddleware.fileSystem, 'vue-ssr-client-manifest.json'))
    if (bundle) {
      ready(bundle, {
        clientManifest
      })
    }
  })
  // hot middleware
  app.use(require('webpack-hot-middleware')(clientCompiler, { heartbeat: 5000 }))

  /****** server ******/

  // watch and update server renderer
  const serverCompiler = webpack(serverConfig)
  // 文件写入内存
  const mfs = new MFS()
  serverCompiler.outputFileSystem = mfs
  serverCompiler.watch({}, (err, stats) => {
    if (err) throw err
    stats = stats.toJson()
    if (stats.errors.length) return

    // read bundle generated by vue-ssr-webpack-plugin
    bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'))

    if (clientManifest) {
      ready(bundle, {
        clientManifest
      })
    }
  })

  return readyPromise
}
