import type { Bot } from 'el-bot'
import fs from 'fs-extra'

/**
 * ref github actions
 * https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow
 */

import type { EventType, MessageType } from 'mirai-ts'
import schedule from 'node-schedule'
import * as shelljs from 'shelljs'
import { parseYaml } from '../../utils/config'
import { handleError } from '../../utils/error'

interface step {
  name?: string
  run?: string
  reply: string | MessageType.MessageChain
}

interface Job {
  name?: string
  steps: step[]
}

type Jobs = Record<string, Job>

type MessageAndEventType =
  | 'message'
  | EventType.EventType
  | MessageType.ChatMessageType

/**
 * 定时格式
 */
interface Schedule {
  cron: string
}

interface On {
  schedule: [Schedule]
}

interface WorkflowConfig {
  name: string
  on: On | MessageAndEventType | MessageAndEventType[]
  jobs: Jobs
}

/**
 * config a workflow
 */
function createWorkflow(ctx: Bot, workflow: WorkflowConfig) {
  const mirai = ctx.mirai
  if (!workflow.on)
    return

  if (Array.isArray(workflow.on)) {
    workflow.on.forEach((on) => {
      trigger(on)
    })
  }
  else if (typeof workflow.on === 'string') {
    trigger(workflow.on)
  }
  else if ((workflow.on as On).schedule) {
    (workflow.on as On).schedule.forEach((singleSchedule) => {
      schedule.scheduleJob(singleSchedule.cron, () => {
        doJobs(workflow.jobs)
      })
    })
  }

  /**
   * 触发
   * @param type
   */
  function trigger(type: MessageAndEventType) {
    mirai.on(type, (msg) => {
      Object.keys(workflow.jobs).forEach((name) => {
        const job = workflow.jobs[name]
        job.steps.forEach((step) => {
          if (msg.reply)
            msg.reply(step.reply)
        })
      })
    })
  }

  /**
   * 运行 jobs 中终端命令
   */
  function doJobs(jobs: Jobs) {
    Object.keys(jobs).forEach((name) => {
      const job = jobs[name]
      job.steps.forEach((step) => {
        if (step.run)
          shelljs.exec(step.run)
      })
    })
  }
}

export default function workflow(ctx: Bot) {
  try {
    const folder = './el/workflows'
    const files = fs.readdirSync(folder)
    files.forEach((file) => {
      const workflow = parseYaml(`${folder}/${file}`)
      if (workflow)
        createWorkflow(ctx, workflow as WorkflowConfig)
    })
  }
  catch (err: any) {
    // 不是 文件不存在 的错误时，才打印出错信息
    if (err && err.code !== 'ENOENT')
      handleError(err)
  }
}
