const argv = require('yargs').argv
const babylon = require('babylon')
const fs = require('fs')
const path = require('path')
/**
 * 字符串操作类，在调用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 fileDir = argv[1]  || '../src/common/' || '../src/views/comment/'

if (fileDir.charAt(1) !== ':') {
  fileDir = path.join(__dirname, fileDir)
}
let fileRegx = /^.(js|vue)$/
traveller(fileDir)
function traveller(fileDir) {
  if (fs.existsSync(fileDir)) {
    let files = fs.readdirSync(fileDir)
    const logs = [];
    files.forEach(fileName => {
      let filePath = path.join(fileDir, fileName)
      let file = fs.statSync(filePath)
      let ext = path.extname(fileName)
      if (file.isDirectory()) {
        traveller(filePath)
      } else if (ext.match(fileRegx)) {
        let fileContent = fs.readFileSync(filePath, 'utf-8')
        let jsContent = fileContent
        if (ext === '.vue') {
          fileContent = fileContent.split(/<\/?script>/)
          jsContent = fileContent[1]
        }
        const source = new StringEditor(jsContent)
        let ast = babylon.parse(jsContent, { 
          sourceType: 'module',
          plugins:[
            "jsx",
            'dynamicImport',
            'classProperties',
            'objectRestSpread'
          ]
        })
        addNamespace(ast, source, filePath, logs)
        if(source.stack.length){
          let transFileContent = source.toString()
          if(ext === '.vue'){
            transFileContent = fileContent[0]+'<script>'+transFileContent+'</script>'+fileContent[2]
          }
          // console.log(transFileContent)
          fs.writeFileSync(filePath, transFileContent);
        }
      }
    })
    console.log(logs.join('\n'))
  }
}

function addNamespace(ast, source, filePath,logs) {
  for (let i = ast.program.body.length - 1; i >= 0; i--) {
    let node = ast.program.body[i]
    switch (node.type) {
      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 + "')"
          let exportExpression = "export default " + moduleRefer + " = "
          logs.push(filePath,' => ',callExpression)
          source.replace(
            node.start,
            node.declaration.start,
            callExpression + '\n' + exportExpression
          )
        }
        break
      }
    }
  }

}
