import autocomplete from '@moyuyc/inquirer-autocomplete-prompt'
import chalk from 'chalk'
import fuzzy from 'fuzzy'
import inquirer, { Answers, ConfirmQuestion, InputQuestion } from 'inquirer'
import jsonFormat from 'json-format'
import ora, { Ora } from 'ora'
import path from 'path'
import { regName } from '../ulits/ulits'
import Base from './base'

interface CreateFs {
  init(): Promise<void>

  makeProjectDir(): Promise<any>

  copyProjectFiles(): void

  modifyAppJson(): Promise<void>

  create(): Promise<Ora>

}

export default abstract class Create extends Base implements CreateFs {
  protected _name: string = ''
  protected _isSubpackage: boolean = false
  protected _selectSubpackage: string = ''
  protected _createMain?: string
  protected _isIndependent?: boolean
  protected newItemRoot: string = ''
  protected newItemJsonRoot: string = ''
  protected newItemJsonName: string = ''

  protected constructor() {
    super()
  }

  public async init(): Promise<void> {
    await this.getAppJson()
    // 注册插件
    inquirer.registerPrompt('autocomplete', autocomplete)
    inquirer.prompt([
      this.__checkName(),
      this.__isSubPackage(),
      this.__modifyName(),
      this.__selectSubPackage(),
      this.__createSubPackage(),
      this.__modifySubPackageChildName(),
      this.__isIndependent()
    ]).then((answers: any) => {
      let {name, isSubpackage, selectSubpackage, createMain, isIndependent} = answers
      this._name = name
      this._isSubpackage = isSubpackage
      this._selectSubpackage = selectSubpackage
      this._createMain = createMain
      this._isIndependent = isIndependent
    }).then(() => this.create()).catch((error) => {
      console.log(error)
    })
  }

  public async create(): Promise<Ora> {
    const loading: Ora = ora(`creating ${this.typeRoot}...`).start()
    loading.text = `创建${this.typeName}目录`
    await this.makeProjectDir()
    loading.text = `正在创建${this.typeName}文件`
    await this.copyProjectFiles()
    loading.text = '正在修改【app.json】文件'
    await this.modifyAppJson()
    return Promise.resolve(loading)
  }

  public async makeProjectDir(): Promise<any> {
    // 默认不分包
    let newItemRoot = path.join(this.projectRoot, this.typeRoot, this._name)
    // 如果分包
    if (this._isSubpackage) {
      let name: string = this._selectSubpackage === '新增分包' && this._createMain ?
        path.join(this.subpackageRoot, this._createMain) :
        this._selectSubpackage
      newItemRoot = path.join(this.projectRoot, name, this.typeRoot, this._name)
    }
    this.newItemRoot = newItemRoot
    // 判断下文件是否存在
    if (!await this.checkFileIsExists(newItemRoot)) this.makeDir(newItemRoot)
  }

  public copyProjectFiles(): void {
    // 读取project.config.json获取配置信息
    this.getProjectConfig().then(async () => {
      const copyRoot = path.join(this.templateRoot, 'component')
      // 复制wxml,json文件
      await this.copyFilesArr(copyRoot, this.newItemRoot, ['index.wxml', 'index.json'])
        .catch(({result}) => this.fileIsRepeat(result))
      // 复制脚本文件
      this._copyTypeFiles(copyRoot, this.projectMode)
      // 复制样式文件
      this._copyTypeFiles(copyRoot, this.projectCss)
    })
  }

  public async modifyAppJson(): Promise<void> {
    // 是否分包
    let newItemJson: string = path.join(this.typeRoot, this._name, 'index').split(path.sep).join('/')
    let newItemName: string = this._name
    if (this._isSubpackage) {
      if (this._selectSubpackage === '新增分包' && this._createMain) {
        this.AppJson.subpackages.push({
          root: path.join(this.subpackageRoot, this._createMain),
          pages: this.typeRoot === 'pages' ? [newItemJson] : [],
          components: this.typeRoot === 'components' ? [newItemJson] : [],
          isIndependent: this._isIndependent
        })
        newItemName = path.join(this._createMain, this._name)
        newItemJson = path.join(this.subpackageRoot, this._createMain, newItemJson)
      } else {
        let index: number = this.subRoots.findIndex(v => v === this._selectSubpackage)
        this.AppJson.subpackages[index][this.typeRoot].push(newItemJson)
        newItemName = path.join(this._selectSubpackage.replace(this.subpackageRoot + '/', ''), this._name)
        newItemJson = path.join(this._selectSubpackage, newItemJson)
      }
    } else {
      this.AppJson[this.typeRoot].push(newItemJson)
    }
    this.newItemJsonRoot = newItemJson.split(path.sep).join('/')
    this.newItemJsonName = newItemName.split(path.sep).join('/')
    await this.writeFile(this.projectRoot, 'app.json', jsonFormat(this.AppJson))
  }

  private async _copyTypeFiles(copyRoot, type): Promise<void> {
    const root: string = path.join(copyRoot, type)
    const files: string[] = await this.readDirs(root)
    await this.copyFilesArr(root, this.newItemRoot, files)
      .catch(({result}) => this.fileIsRepeat(result))
  }

  // 验证名称
  private __checkName(): InputQuestion<Answers> {
    return {
      type: 'input',
      name: 'name',
      message: `请输入${this.typeName}名：`,
      validate: (input: string): Promise<boolean | string> => {
        return new Promise<boolean | string>((resolve) => {
          // 验证名是否正确
          if (!regName.test(input)) resolve(chalk.red(`输入的${this.typeName}名不正确！`))
          resolve(true)
        })
      }
    }
  }

  // 是否分包
  private __isSubPackage(): ConfirmQuestion<Answers> {
    return {
      type: 'confirm',
      name: 'isSubpackage',
      message: `当前${this.typeName}是否分包：`,
      default: false
    }
  }

  // 如果不分包，判断是否重复
  private __modifyName(): InputQuestion<Answers> {
    return {
      type: 'input',
      name: 'name',
      message: answer => `【${this.typeRoot}】中已存在【${answer.name}】${this.typeName}，请重新输入${this.typeName}名：`,
      when: answer => {
        return !answer.isSubpackage &&
          this.mainRoots.find(v => v === answer.name) !== undefined
      },
      validate: (input: string): Promise<boolean | string> => {
        return new Promise<boolean | string>(resolve => {
          if (this.mainRoots.find(v => v === input)) resolve(chalk.red(`${this.typeName}名重复，请更换！`))
          resolve(true)
        })
      }
    }
  }

  // 选择分包
  private __selectSubPackage(): object {
    return {
      type: 'autocomplete',
      name: 'selectSubpackage',
      message: `选择${this.typeName}所属分包：`,
      choices: [],
      suggestOnly: false,
      source: (_answers, input: string) => {
        return Promise.resolve(fuzzy.filter(input, ['新增分包', ...this.subRoots]).map(e => e.original))
      },
      when: (answer) => {
        return answer.isSubpackage &&
          this.subRoots.length >= 0
      }
    }
  }

  // 创建分包
  private __createSubPackage(): InputQuestion<Answers> {
    return {
      type: 'input',
      name: 'createMain',
      message: '创建新的分包：',
      when: (answer) => {
        return answer.isSubpackage &&
          this.subRoots.length <= 0 ||
          answer.selectSubpackage === '新增分包'
      },
      validate: (input: string): Promise<boolean | string> => {
        return new Promise<boolean | string>(resolve => {
          // 验证名是否正确
          if (!regName.test(input)) {
            resolve(chalk.red('输入的分包名不正确！'))
          }// 检查分包名是否重复
          else if (this.subRoots.find(v => v === input)) resolve(chalk.red('该分包已存在，请换个分包名！'))
          resolve(true)
        })
      }
    }
  }

  // 分包下的子包如果重复则需要修改子包名
  private __modifySubPackageChildName(): InputQuestion<Answers> {
    return {
      type: 'input',
      name: 'name',
      message: answer => `【${answer.selectSubpackage}】分包已存在【${answer.name}】${this.typeName}，请更换${this.typeName}名：`,
      when: answer => {
        return answer.isSubpackage &&
          answer.selectSubpackage !== '新增分包' &&
          this.subChild[answer.selectSubpackage].find(v => v === answer.name) !== undefined
      },
      validate: (input: string, answers: any): Promise<boolean | string> => {
        return new Promise<boolean | string>(resolve => {
          // 验证名是否正确
          if (!regName.test(input)) {
            resolve(chalk.red(`输入的${this.typeName}名不正确！`))
          }// 验证是否重复
          else if (this.subChild[answers.selectSubpackage].find(v => v === input)) {
            resolve(chalk.red(`${this.typeName}名重复，请更换${this.typeName}名！`))
          }
          resolve(true)
        })
      }
    }
  }

  // 新增分包是否为独立分包
  private __isIndependent(): ConfirmQuestion<Answers> {
    return {
      type: 'confirm',
      name: 'isIndependent',
      message: '是否设置独立分包：',
      default: false,
      when: (answers) => {
        return answers.isSubpackage &&
          answers.selectSubpackage === '新增分包' &&
          answers.createMain
      }
    }
  }

}
