import ora from 'ora'
import fs from 'fs'

import { config, dirMap, targetRoot, resolveTmp } from 'config/global'
import { writeFileEjs } from 'utils/useEjs'
import { select } from 'utils/useCmd'
import { compilePath, existsFileCover, resolve, errLog } from 'utils/tool'

import type { CommanderStatic } from 'commander'

export function vuecpnCommand(program: CommanderStatic): void {
  program
    .command('vuecpn [cpnName]')
    .description('创建vue组件, vuecpn [cpnName] [-d cpnDir]')
    .action(async (cpnName: string) => {
      if (cpnName) {
        createCpn(cpnName)
      } else {
        const cpnDesc = await select(Object.keys(dirMap), '请选择公共组件类型:')
        createCpn(dirMap[cpnDesc], true)
      }
    })

  /**
   * @param cpnName 生成组件名称或公共组件目录
   * @param isPub 是否来自公共组件模板
   */
  async function createCpn(cpnName: string, isPub?: boolean) {
    const spinner = ora(`创建${cpnName}${isPub ? '公共' : ''}组件...`)

    try {
      const { dest } = program.opts()
      let targetDir: string = dest ? `components/${dest}` : 'components'
      let cpnNameTmp
      if (isPub) {
        const rootDir: string[] = fs.readdirSync(resolve(resolveTmp, 'vue', 'components', cpnName))
        const cpnDir = rootDir.map((file) => file.split('.')[0])
        targetDir = `components/${config.publicComponentDir}`
        cpnNameTmp = await select(cpnDir, '请选择要添加的公共组件:')
      }
      spinner.start()

      const lowerName = cpnName.toLowerCase()

      const targetPath = resolve(targetRoot, targetDir)

      compilePath(targetPath)

      const filePath = resolve(targetPath, `${isPub ? cpnNameTmp : cpnName}.vue`)
      const proceed = await existsFileCover(filePath, spinner)

      if (proceed) {
        if (isPub) {
          await writeFileEjs(resolve(resolveTmp, `vue/components/${cpnName}/${cpnNameTmp}.ejs`), filePath)
        } else {
          await writeFileEjs(resolve(resolveTmp, 'vue/cpn.ejs'), filePath, {
            name: cpnName,
            lowerName,
          })
        }

        spinner.succeed('创建成功')
      }
    } catch (err) {
      spinner.fail('创建失败')
      err && errLog(err)
    }
  }
}
