// import nodewindows from 'node-windows'
import cluster from 'cluster'
import bunyan from 'bunyan-lite'
import { setTimeout } from 'timers/promises'

export function getDefaultStreams() {
  if (process.env.NODE_ENV === 'production') {
    return [{
        path: 'log.log',
        level: 'info',
      }
    ]
  } else {
    return [{
        "stream": process.stdout,
        "level": "debug"
      }
    ]
  }
}

export default function getLog(name, streams = null, opts = {}) {
  let settings
  let ringbuffer = new bunyan.RingBuffer({ limit: 100 })
  let ringbufferwarn = new bunyan.RingBuffer({ limit: 100 })

  if (streams) {
    streams.forEach(function(stream) {
      if (stream.stream === 'process.stdout') {
        stream.stream = process.stdout
      }
    })
  }

  settings = {
    name: name,
    streams: streams || getDefaultStreams()
  }

  let logger

  settings.streams.push({
    stream: ringbuffer,
    type: 'raw',
    level: 'info',
  })

  settings.streams.push({
    stream: ringbufferwarn,
    type: 'raw',
    level: 'warn',
  })

  settings.streams.push({
    stream: {
      write: function(record) {
        logger.emit('newlog', record)

        if (cluster.isWorker) {
          process.send({
            apptarget: opts.name || name,
            type: 'newlog',
            payload: record,
          })
        }
      },
      end: function() {},
      destroy: function() {},
      destroySoon: function() {},
    },
    type: 'raw',
    level: 'info',
  })

  let eventManager = null
  let eventManagerLoading = false

  async function safeLoadEvent(level, message, code) {
    if (eventManager === false) {
      return Promise.resolve()
    }

    if (!eventManager) {
      if (eventManagerLoading) {
        for (let i = 0; i < 10 && eventManagerLoading; i++) {
          await setTimeout(50)
        }
        if (eventManagerLoading) {
          eventManager = false
        }
        return safeLoadEvent(level, message, code)
      }

      eventManagerLoading = true

      let prom
      if (opts.import) {
        prom = opts.import('node-windows')
      } else {
        prom = import('node-windows')
      }
      await prom.then(
        function(res) { eventManager = new res.default.EventLogger(name) },
        function() { eventManager = false },
      )
      eventManagerLoading = false
      return safeLoadEvent(level, message, code)
    }

    return new Promise(function(res) {
      try {
        eventManager[level](message, code, function() { res() })
      } catch {
        res()
      }
    })
  }

  // Create our logger.
  logger = bunyan.createLogger(settings)

  if (process.env.NODE_ENV === 'production') {
    logger.event = {
      info: safeLoadEvent.bind(this, 'info'),
      warn: safeLoadEvent.bind(this, 'warn'),
      error: safeLoadEvent.bind(this, 'error'),
    }
  } else {
    logger.event = {
      info: function() { return Promise.resolve() },
      warn: function() { return Promise.resolve() },
      error: function() { return Promise.resolve() },
    }
  }
  logger.on('error', function(err) {
    if (process.env.NODE_ENV === 'production') {
      logger.event.warn(`Error in logger ${name}: ${err.message}`)
    } else {
      console.log(`Error in logger ${name}: ${err.message}`)
    }
  })
  logger.ringbuffer = ringbuffer
  logger.ringbufferwarn = ringbufferwarn

  return logger
}
