const cluster = require('cluster')
const Promise = require('bluebird')
const _ = require('lodash')

/* global wiki */

module.exports = {
  numWorkers: 1,
  workers: [],
  init() {
    if (cluster.isMaster) {
      wiki.logger.info('=======================================')
      wiki.logger.info('= Wiki.js =============================')
      wiki.logger.info('=======================================')

      wiki.redis = require('./redis').init()
      wiki.queue = require('./queue').init()

      this.setWorkerLimit()
      this.bootMaster()
    } else {
      this.bootWorker()
    }
  },
  /**
   * Pre-Master Boot Sequence
   */
  preBootMaster() {
    return Promise.mapSeries([
      () => { return wiki.db.onReady },
      () => { return wiki.configSvc.loadFromDb() },
      () => { return wiki.queue.clean() }
    ], fn => { return fn() })
  },
  /**
   * Boot Master Process
   */
  bootMaster() {
    this.preBootMaster().then(sequenceResults => {
      if (_.every(sequenceResults, rs => rs === true)) {
        this.postBootMaster()
      } else {
        wiki.logger.info('Starting configuration manager...')
        require('../configure')()
      }
      return true
    }).catch(err => {
      wiki.logger.error(err)
      process.exit(1)
    })
  },
  /**
   * Post-Master Boot Sequence
   */
  postBootMaster() {
    require('../master')().then(() => {
      _.times(this.numWorker, this.spawnWorker)

      wiki.queue.uplClearTemp.add({}, {
        repeat: { cron: '*/15 * * * *' }
      })
    })

    cluster.on('exit', (worker, code, signal) => {
      wiki.logger.info(`Background Worker #${worker.id} was terminated.`)
    })
  },
  /**
   * Boot Worker Process
   */
  bootWorker() {
    wiki.logger.info(`Background Worker #${cluster.worker.id} is initializing...`)
    require('../worker')
  },
  /**
   * Spawn new Worker process
   */
  spawnWorker() {
    this.workers.push(cluster.fork())
  },
  /**
   * Set Worker count based on config + system capabilities
   */
  setWorkerLimit() {
    const numCPUs = require('os').cpus().length
    this.numWorkers = (wiki.config.workers > 0) ? wiki.config.workers : numCPUs
    if (this.numWorkers > numCPUs) {
      this.numWorkers = numCPUs
    }
  }
}