/*
import foo from './compname.vue'
import {bar, baz} from '../../libname.js'
转换为下面这种写法
const foo = zving.views.dirname.compname
const {bar, baz} = zving.lib.libname
*/
const argv = require('yargs').argv
const babylon = require('babylon')
const fs = require('fs')
const path = require('path')
const mkdirp = require('mkdirp')

let inputFilePath = argv[1] || '20190418导给冯晨大学生在线项目.txt'

/**
 * 字符串操作类，在调用replace时不会真正的替换，而只是记录要替换的位置，在调用toString时才进行替换，并返回替换后的新的字符串
 */
class StringEditor {
  constructor(content, start, end) {
    this.content = content
    this.start = start || 0
    this.end = end || content.lengt
    this.stack = []
  }

  /**
   * 记录要替换的字符的位置和新字符串
   */
  replace(start, end, newString) {
    this.stack.push({
      range: [start, end],
      newString: newString
    })
    return this.stack.length - 1
  }
  /**
   * 同String.prototype.slice
   */
  slice(start, end) {
    return this.content.slice(start, end)
  }
  /**
   * 完成字符串替换并返回结果
   */
  toString() {
    var value = ''
    var start = this.start
    this.stack = this.stack.sort(function (a, b) {
      return a.range[0] - b.range[0]
    })
    for (var i = this.stack.length - 1; i >= 0; i--) {
      // 删除掉被其他range包含的range
      var action = this.stack[i]
      var prevAction = this.stack[i - 1]
      if (
        prevAction &&
        action.range[0] >= prevAction.range[0] &&
        action.range[1] <= prevAction.range[1]
      ) {
        this.stack.splice(i, 1)
      }
    }
    for (i = 0; i < this.stack.length; i++) {
      action = this.stack[i]
      value += this.content.substring(start, action.range[0])
      value += action.newString.toString()
      start = action.range[1]
    }

    value += this.content.substring(start, this.end)
    return value
  }
}

let filePaths
if (!inputFilePath.endsWith('.txt')){
  filePaths = [inputFilePath]
} else {
  filePaths = fs.readFileSync(path.join(__dirname, inputFilePath), 'utf-8')
  filePaths = filePaths.trim().split(/[\r\n]/)
}
for (let i = filePaths.length - 1; i >= 0; i--){
  let filePath = filePaths[i]
  if (!filePath){
    filePaths.splice(i, 1)
    continue
  }
  if (filePath.charAt(1) !== ':') {
    filePaths[i] = path.join(__dirname, filePath)
  }
}
const logs = []
const today = (new Date()).toISOString().split('T')[0]
for (let i = 0; i < filePaths.length; i++){
  let filePath = filePaths[i]
  if (filePath.charAt(1) !== ':') {
    filePath = path.join(__dirname, filePath)
  }
  let ext = path.extname(filePath)
  let fileContent = fs.readFileSync(filePath, 'utf-8')
  let jsContent = fileContent
  if (ext === '.vue') {
    fileContent = fileContent.split(/<\/?script[^>]*>/)
    jsContent = (fileContent[1]||'')
  }
  let outputPath = filePath.replace('\\src\\', '\\outputForSecondaryDevelopment\\' + today + '\\')
  mkdirp.sync(outputPath.replace(/\\[^\\]+$/, ''))

  if (jsContent.trim().length){
    const source = new StringEditor(jsContent)

    let ast = babylon.parse(jsContent, {
      sourceType: 'module',
      plugins: [
        'jsx',
        'dynamicImport',
        'classProperties',
        'objectRestSpread'
      ]
    })

    exportForScndDvlp(ast, source, filePath)

    if (source.stack.length) {
      let transFileContent = source.toString()
      if (ext === '.vue') {
        transFileContent = fileContent[0] + '<script>' + transFileContent + '</script>' + fileContent[2]
      }
      // console.log(transFileContent)
      fs.writeFileSync(outputPath, transFileContent)
    } else {
      fs.writeFileSync(outputPath, fileContent)
    }
  }else{
    fs.copyFileSync(filePath, outputPath)
  }
}

console.log(logs.join('\n'))

function exportForScndDvlp(ast, source, filePath) {
  for (let i = ast.program.body.length - 1; i >= 0; i--) {
    let node = ast.program.body[i]
    switch (node.type) {
      case 'ImportDeclaration': {
        if (node.source.value.match(/^(@src|\.+)\/.+(\.js|\.vue|\.css)?$/)) {
          let modulePath
          if (node.source.value.startsWith('@src/')){
            modulePath = path.join(path.join(__dirname, '../src'), node.source.value.slice(5))
          } else {
            modulePath = path.join(filePath.replace(/\\[^\\]+$/, ''), node.source.value)
          }
          if (!modulePath.match(/.+\.\w+$/)){
            if(fs.existsSync(modulePath + '.js')){
              modulePath = modulePath + '.js'
            }else if(fs.existsSync(modulePath + '.vue')){
              modulePath = modulePath + '.vue'
            }else if(fs.existsSync(modulePath + '\\index.js')){
              modulePath = modulePath + '\\index.js'
            }else{
              console.error('无法找到import的内容',modulePath)
            }
          }
          if (filePaths.includes(modulePath)){
            break
          }
          if (!modulePath.match(/.+(\.js|\.vue)/)){ // css 文件直接复制过去
            let outputPath = modulePath.replace('\\src\\', '\\outputForSecondaryDevelopment\\' + today + '\\')
            mkdirp.sync(outputPath.replace(/\\[^\\]+$/, ''))
            fs.copyFileSync(modulePath, outputPath)
            break
          }
          modulePath = path.relative(path.join(__dirname, '../src'), modulePath)
          let moduleRefer = 'zving.' + modulePath.replace(/\.\w+$/, '').replace(/\\/g, '.')
          // 特殊符号要改，如 zving.components.nw-corner-button 转成 zving.components.nwCornerButton
          moduleRefer = moduleRefer.replace(/[^.\w]+(\w)/g, (a, b, c, d) => {
            return b.toUpperCase()
          })
          let variable = []
          if (node.specifiers.length === 1) {
            variable = node.specifiers[0].local.name
          } else {
            for (let j = 0; j < node.specifiers.length; j++) {
              variable.push(node.specifiers[j].local.name)
            }
            variable = '{ ' + variable.join(', ') + ' }'
          }
          let transform = 'const ' + variable + ' = ' + moduleRefer
          logs.push('import -> let: ' + moduleRefer)
          source.replace(
            node.start,
            node.end,
            transform
          )
        }
        break
      }
      case 'ExportDefaultDeclaration': {
        if (node.declaration.type === 'ObjectExpression' || node.declaration.type === 'Identifier') {
          let modulePath = path.relative(path.join(__dirname, '../src'), filePath)
          let moduleRefer = 'zving.' + modulePath.replace(/\.\w+$/, '').replace(/\\/g, '.')
          let callExpression = "window.namespace('" + moduleRefer.replace(/\.\w+$/, '') + "')"
          let exportExpression = '\nexport default ' + moduleRefer
          let assignPre = ' = Object.assign(' + moduleRefer + ', '
          let assignPost = ')'
          logs.push('export -> assign: ' + moduleRefer)
          source.replace(
            node.start,
            node.declaration.start,
            callExpression + exportExpression + assignPre
          )
          source.replace(
            node.end,
            node.end,
            assignPost
          )
        }
        break
      }
    }
  }
}
