const path = require('path')

const {
  hyphenate,
  isComponent
} = require('./util')

const {
  removeExt
} = require('@dcloudio/uni-cli-shared/lib/util')

const {
  getAutoComponents
} = require('@dcloudio/uni-cli-shared/lib/pages')

const {
  updateUsingAutoImportComponents
} = require('@dcloudio/uni-cli-shared/lib/cache')

function formatSource (source) {
  if (source.indexOf('@/') === 0) { // 根目录
    source = source.replace('@/', '')
  } else { // node_modules
    if (process.env.UNI_PLATFORM === 'mp-alipay') {
      if (source.indexOf('@') === 0) {
        source = source.replace('@', 'npm-scope-')
      }
    }
    source = 'node-modules/' + source
  }
  return removeExt(source)
}

function getWebpackChunkName (source) {
  return formatSource(source)
}

function updateMPUsingAutoImportComponents (autoComponents, options) {
  if (!options.resourcePath) {
    return
  }
  const resourcePath = options.resourcePath.replace(path.extname(options.resourcePath), '')
  if (resourcePath === 'App') {
    return
  }
  const usingAutoImportComponents = Object.create(null)
  autoComponents.forEach(({
    name,
    source
  }) => {
    // 自定义组件统一格式化为 kebab-case
    usingAutoImportComponents[hyphenate(name)] = '/' + formatSource(source)
  })
  updateUsingAutoImportComponents(resourcePath, usingAutoImportComponents) // 更新json
}

function generateAutoComponentsCode (autoComponents, dynamic = false) {
  const components = []
  autoComponents.forEach(({
    name,
    source
  }) => {
    // 统一转换为驼峰命名
    name = name.replace(/-(\w)/g, (_, str) => str.toUpperCase())
    if (dynamic) {
      components.push(
        `'${name}': function(){return import(/* webpackChunkName: "${getWebpackChunkName(source)}" */'${source}')}`
      )
    } else {
      components.push(`'${name}': require('${source}').default`)
    }
  })
  if (process.env.NODE_ENV === 'production') {
    return `var components = {${components.join(',')}}`
  }
  return `var components;
try{
  components = {${components.join(',')}}
}catch(e){
  if(e.message.indexOf('Cannot find module') !== -1 && e.message.indexOf('.vue') !== -1){
    console.error(e.message)
    console.error('1. 排查组件名称拼写是否正确')
    console.error('2. 排查组件是否符合 easycom 规范，文档：https://uniapp.dcloud.net.cn/collocation/pages?id=easycom')
    console.error('3. 若组件不符合 easycom 规范，需手动引入，并在 components 中注册该组件')
  } else {
    throw e
  }
}`
}

function compileTemplate (source, options, compile) {
  const res = compile(source, options)
  const autoComponents = getAutoComponents([...(options.isUnaryTag.autoComponents || [])])
  if (autoComponents.length) {
    // console.log('检测到的自定义组件:' + JSON.stringify(autoComponents))
    res.components = generateAutoComponentsCode(autoComponents, options.mp)
  } else {
    res.components = 'var components;'
  }
  if (options.mp) { // 小程序 更新 json 每次编译都要调整,保证热更新时增减组件一致
    updateMPUsingAutoImportComponents(autoComponents || [], options)
  }
  return res
}

const compilerModule = {
  preTransformNode (el, options) {
    if (el.tag === 'match-media' && process.env.UNI_PLATFORM !== 'mp-weixin') {
      el.tag = 'uni-match-media'
    }
    if (process.env.UNI_PLATFORM === 'quickapp-native') {
      // 排查所有标签
      (options.isUnaryTag.autoComponents || (options.isUnaryTag.autoComponents = new Set())).add(el.tag)
    } else if (isComponent(el.tag, options.mp.platform) && el.tag !== 'App') { // App.vue
      // 挂在 isUnaryTag 上边,可以保证外部访问到
      (options.isUnaryTag.autoComponents || (options.isUnaryTag.autoComponents = new Set())).add(el.tag)
    }
  }
}
module.exports = {
  compileTemplate,
  module: compilerModule
}
