import { Body, Get, Controller, Param, Post, Put, QueryParam, Delete } from '@gem-mine/routing-controllers'
import * as launch from 'launch-code-editor'
import Project from '../service/project'
import { pagination, LIMIT } from '../util/model'

const util = require('util')
const path = require('path')
const fs = require('fs-extra')
const exec = util.promisify(require('child_process').exec)

export type SubTemplateInfo = {
  name: string,
  version: string
}

export type ProjectInfo = {
  name: string,
  path: string,
  choice: string,
  env: string,
  version: string,
  user: string,
  email: string,
  template_id: string,
  project_id: string,
  subTemplateList: Array<SubTemplateInfo>
}

@Controller('/project')
export default class {
  @Get('/')
  async getList(
    @QueryParam('path')
    path: string = '',

    @QueryParam('project_id')
    projectId: string,

    @QueryParam('offset')
    offset: number = 0,
    
    @QueryParam('limit')
    limit: number = LIMIT
  ) {
    const query = await Project.getList({ path, projectId, offset, limit })
    const result = pagination({ query, offset, limit })
    return result
  }

  @Post('/')
  async createOne(@Body() modal: ProjectInfo) {
    const data = await Project.createOne(modal)
    return data
  }

  @Get('/:id')
  async getOne(@Param('id') id: string) {
    const data = await Project.getOne(id)
    return { data }
  }

  @Put('/:id')
  async updateOne(@Param('id') id: string, @Body() { name, env, version, star }: { name: string, env: string, version: string, star: number }) {
    const data = await Project.updateOne(id, { name, env, version, star })
    return { data }
  }

  @Delete('/:id')
  async deleteOne(@Param('id') id: string) {
    const resp = await Project.getOne(id)
    const path = resp.path
    if (fs.existsSync(path)) {
      fs.renameSync(path, `${path}_delete`)
    }
    const data = await Project.deleteOne(id)
    return data
  }

  @Post('/generate')
  async generate(@Body() modal: ProjectInfo) {
    const targetPath = modal.path
    fs.ensureDirSync(targetPath)
    const data = await Project.createOne(modal)
    await exec(`gem-mine-cli generate -c --name ${modal.name} -d`, {
      cwd: path.join(targetPath),
      windowsHide: true
    })
    return {
      data
    }
  }

  @Post('/upgrade')
  async upgrade(@Body() modal: { path: string }) {
    const targetPath = modal.path
    const exist = fs.existsSync(targetPath)
    if (exist) {
      await exec(`gem-mine-cli generate -d`, {
        cwd: path.join(targetPath),
        windowsHide: true
      })
      return {
        success: true
      }
    } else {
      return {
        exists: false
      }
    }
  }

  @Post('/open')
  async open(@Body() modal: { path: string, editor: string }) {
    const { path, editor } = modal
    if (!fs.existsSync(path)) {
      return {
        success: false,
        message: '文件打开失败，请检查本地文件路径是否正确'
      }
    }
    try {
      await launch(`${path}`, editor)
      return {
        success: true
      }
    } catch (error) {
      // 硬编码 绕过 launch-code-editor 异常
      if (error.message.indexOf('Cannot destructure property') > -1) {
        return { success: true }
      }
      return {
        success: false,
        message: '文件打开失败，请检查本地文件路径是否正确；编辑器是否已安装！'
      }
    }
  }
}
