import * as EventEmitter from 'events'
import * as SocketIO from 'socket.io'
import * as getUpgradeTask from '@gem-mine/cli/lib/command/upgrade'
import * as getCreateTask from '@gem-mine/cli/lib/command/create'
import * as getAddTask from '@gem-mine/cli/lib/command/add'
import { logger, progress } from '@gem-mine/cli-share-lib'

type CliTask = {
  run: () => Promise<void>,
  event: EventEmitter,
  logger: EventEmitter
}

type GetCLiTask = (
  options: object | undefined
) => Promise<CliTask>

const TaskMap = {
  create: <GetCLiTask>getCreateTask,
  upgrade: <GetCLiTask>getUpgradeTask,
  add: <GetCLiTask>getAddTask,
}

/**
 * 处理CMD相关事件
 * @param socket
 */
export default function registerCliHandler(socket: SocketIO.Socket) {
  bindCliEvent(socket)
   // 执行升级指令
  socket.on('cli:task', async (
    type: string,
    options: Array<string> = []
  ) => {
    const getTask = TaskMap[type]
    if(!getTask) {
      socket.emit('cli.error', {
        message: `No such type ${type}`
      })
      return
    }
    const task: CliTask = await getTask(options)
    bindPromptEvent(socket, task)
    try {
      await task.run()
    } catch(e) {
      socket.emit('cli.error', {
        message: e.stack
      })
      return
    }
    socket.emit('cli.end')
  })
}

/**
 * 注册Prompt监听事件，task.event转发给socket
 * @param socket 
 * @param task 
 */
function bindPromptEvent(socket: SocketIO.Socket, task: CliTask) {
  const event = task.event
  event.on('prompt', (...args) => {
    socket.once('cli.answer', (answser) => {
      event.emit('answer', answser)
    })
    socket.emit('cli.prompt', ...args)
  })
}

/**
 * 绑定通用的事件，只需要绑定一次
 * @param socket 
 */
function bindCliEvent(socket: SocketIO.Socket) {
  logger.on('log', (message) => {
    socket.emit('cli.console.log', message)
  })
  logger.on('warn', (message) => {
    socket.emit('cli.console.warn', message)
  })
  logger.on('error', (message) => {
    socket.emit('cli.console.error', message)
  })
  logger.on('errorStack', (message) => {
    socket.emit('cli.console.errorStack', message)
  })

  // yarn 安装进度
  progress.on('progress', (value) => {
    socket.emit('cli.progress.value', value)
  })

  progress.on('log', (value) => {
    socket.emit('cli.progress.log', value)
  })
}