const fs = require('fs')
const path = require('path')
const hash = require('hash-sum')
const loaderUtils = require('loader-utils')

const {
  parse
} = require(require.resolve('@vue/component-compiler-utils', {
  paths: [require.resolve('vue-loader')]
})) // 确保使用的与 vue-loader 一致

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

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

const preprocessor = require('@dcloudio/vue-cli-plugin-uni/packages/webpack-preprocess-loader/preprocess')

const traverse = require('@dcloudio/webpack-uni-mp-loader/lib/babel/global-component-traverse')

const genStylesCode = require('../../vue-loader/lib/codegen/styleInjection')

const {
  parseComponents
} = require('./util')

function getDefineComponents ({
  components
}) {
  return components.map(({
    name,
    source
  }) => `Vue.component('${name}',require('${source}').default)`)
}

const appVueFilePath = path.resolve(process.env.UNI_INPUT_DIR, 'App.vue')

function getStylesCode (loaderContext) {
  if (!fs.existsSync(appVueFilePath)) {
    return
  }
  const source = fs.readFileSync(appVueFilePath, 'utf8')
  const {
    minimize,
    sourceMap,
    rootContext,
    resourcePath,
    resourceQuery
  } = loaderContext

  const options = loaderUtils.getOptions(loaderContext) || {}

  const filename = path.basename(resourcePath)
  const context = rootContext || process.cwd()
  const sourceRoot = path.dirname(path.relative(context, resourcePath))
  const descriptor = parse({
    source,
    compiler: options.compiler,
    filename,
    sourceRoot,
    needMap: sourceMap
  })

  // styles
  let stylesCode = ''
  if (descriptor.styles.length) {
    const isProduction = options.productionMode || minimize || process.env.NODE_ENV === 'production'

    const stringifyRequest = r => loaderUtils.stringifyRequest(loaderContext, r)

    // module id for scoped CSS & hot-reload
    const rawShortFilePath = path
      .relative(context, resourcePath)
      .replace(/^(\.\.[/\\])+/, '')

    const shortFilePath = rawShortFilePath.replace(/\\/g, '/') + resourceQuery

    const needsHotReload = false

    const id = hash(
      isProduction
        ? (shortFilePath + '\n' + source)
        : shortFilePath
    )
    stylesCode = genStylesCode(
      loaderContext,
      descriptor.styles,
      id,
      resourcePath,
      stringifyRequest,
      needsHotReload,
      true, // needs explicit injection?
      'app-vue'
    )
  }
  return stylesCode.replace(/main\.[jt]s/g, 'App.vue')
}

module.exports = function (source, map) {
  // 需要执行一遍条件编译 source
  if (source.indexOf('#ifdef') !== -1) {
    source = preprocessor.preprocess(source, jsPreprocessOptions.context, {
      type: jsPreprocessOptions.type
    })
  }
  // 追加小程序全局自定义组件(仅v3)
  source = getGlobalUsingComponentsCode() + source
  const automatorCode = process.env.UNI_AUTOMATOR_WS_ENDPOINT
    ? 'import \'@dcloudio/uni-app-plus/dist/automator.view\''
    : ''
  this.callback(null,
    `
// @ts-nocheck
import 'uni-pages?${JSON.stringify({ type: 'view' })}'
${automatorCode}
function initView(){
    ${getStylesCode(this)}
    typeof injectStyles ==='function' && injectStyles()
    ${getDefineComponents(parseComponents(source, traverse)).join('\n')}
    UniViewJSBridge.publishHandler('webviewReady')
}
if(typeof plus !== 'undefined'){
  initView()
} else {
  document.addEventListener('plusready',initView)
}
`,
    map)
}
