const fs = require('fs')
const path = require('path')

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

const {
  SCSS,
  SASS
} = require('./scss')

const uniRuntime = '@dcloudio/vue-cli-plugin-uni/packages/mp-vue'
const mpvueRuntime = '@dcloudio/vue-cli-plugin-uni/packages/mpvue'
const megaloRuntime = '@dcloudio/vue-cli-plugin-uni/packages/megalo'

const uniCompiler = '@dcloudio/uni-template-compiler'
const mpvueCompiler = '@dcloudio/vue-cli-plugin-uni/packages/mpvue-template-compiler'
const megaloCompiler = '@megalo/template-compiler'

function getShadowCss () {
  let tagName = 'page'
  if (process.env.UNI_PLATFORM === 'h5') {
    tagName = 'body'
  }
  return `${tagName}::after{position:fixed;content:'';left:-1000px;top:-1000px;-webkit-animation:shadow-preload .1s;-webkit-animation-delay:3s;animation:shadow-preload .1s;animation-delay:3s}@-webkit-keyframes shadow-preload{0%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}100%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}}@keyframes shadow-preload{0%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}100%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}}`
}

function getCopyOption (file, options) {
  if (file === 'wxcomponents') {
    if (!options) {
      options = {}
    }
    // 不拷贝vue,css(这些可能是 uni-migration 转换二来的)
    options.ignore = ['**/*.vue', '**/*.css']
  }
  if (path.isAbsolute(file)) {
    if (fs.existsSync(file)) {
      return Object.assign({
        from: file,
        to: path.resolve(process.env.UNI_OUTPUT_DIR)
      }, options)
    }
  }
  const from = path.resolve(process.env.UNI_INPUT_DIR, file)
  if (fs.existsSync(from)) {
    return Object.assign({
      from,
      to: path.resolve(process.env.UNI_OUTPUT_DIR, file)
    }, options)
  }
}

function getCopyOptions (files, options = {}, subPackages = true) {
  const copyOptions = []
  files.forEach(file => {
    // 主包
    const copyOption = getCopyOption(file, options)
    if (copyOption) {
      copyOptions.push(copyOption)
    }
    if (subPackages) {
      // 分包
      Object.keys(process.UNI_SUBPACKAGES).forEach(root => { // 分包静态资源
        const subCopyOption = getCopyOption(path.join(root, file), options)
        if (subCopyOption) {
          copyOptions.push(subCopyOption)
        }
      })
    }
  })
  return copyOptions
}

function getStaticCopyOptions (assetsDir) {
  const ignore = []

  Object.keys(PLATFORMS).forEach(platform => {
    if (process.env.UNI_PLATFORM !== platform) {
      ignore.push(platform + '/**/*')
    }
  })

  return getCopyOptions(
    [assetsDir], {
      ignore
    }
  )
}

const PLATFORMS = {
  'h5': {
    global: '',
    exts: false,
    vue: '@dcloudio/vue-cli-plugin-uni/packages/h5-vue',
    compiler: false,
    megalo: false,
    filterTag: 'wxs',
    subPackages: false,
    cssVars: {
      '--status-bar-height': '0px'
    },
    copyWebpackOptions ({
      assetsDir
    }) {
      return [
        ...getStaticCopyOptions(assetsDir),
        {
          from: require.resolve('@dcloudio/uni-h5/dist/index.css'),
          to: assetsDir,
          transform (content) {
            if (process.env.NODE_ENV === 'production') {
              return content + getShadowCss()
            }
            return content
          }
        },
        ...getCopyOptions(['hybrid/html'])
      ]
    }
  },
  'app-plus': {
    global: 'wx',
    exts: {
      style: '.wxss',
      template: '.wxml',
      filter: '.wxs'
    },
    vue: mpvueRuntime,
    compiler: mpvueCompiler,
    megalo: false,
    filterTag: 'wxs',
    subPackages: false,
    cssVars: {
      '--window-top': '0px'
    },
    copyWebpackOptions ({
      assetsDir,
      vueOptions
    }) {
      if (
        vueOptions &&
        vueOptions.pluginOptions &&
        vueOptions.pluginOptions['uni-app-plus'] &&
        vueOptions.pluginOptions['uni-app-plus']['view']
      ) { // app-view 无需拷贝资源(app-service 已经做了)
        return []
      }

      const files = ['hybrid/html']
      let wxcomponents = []
      if (!process.env.UNI_USING_NATIVE && !process.env.UNI_USING_V3) {
        wxcomponents = getCopyOptions(['wxcomponents'], {
          to: path.resolve(process.env.UNI_OUTPUT_TMP_DIR, 'wxcomponents')
        })
      }
      let template = []
      let view = []
      if (process.env.UNI_USING_V3) {
        view = getCopyOptions([
          require.resolve('@dcloudio/uni-app-plus/dist/view.css'),
          require.resolve('@dcloudio/uni-app-plus/dist/view.umd.min.js')
        ])
        template = [
          ...getCopyOptions([path.resolve(__dirname, '../template/common')]),
          ...getCopyOptions([path.resolve(__dirname, '../template/v3')])
        ]
      }
      return [
        ...view,
        ...template,
        ...getStaticCopyOptions(assetsDir),
        ...wxcomponents,
        ...getCopyOptions(files)
      ]
    }
  },
  'mp-qq': {
    global: 'wx',
    exts: {
      style: '.qss',
      template: '.qml',
      filter: '.wxs'
    },
    vue: mpvueRuntime,
    compiler: mpvueCompiler,
    megalo: false,
    filterTag: 'wxs',
    subPackages: true,
    cssVars: {
      '--status-bar-height': '25px',
      '--window-top': '0px',
      '--window-bottom': '0px'
    },
    project: 'project.config.json',
    copyWebpackOptions ({
      assetsDir
    }) {
      return [
        ...getStaticCopyOptions(assetsDir),
        ...getCopyOptions(['wxcomponents'])
      ]
    }
  },
  'mp-weixin': {
    global: 'wx',
    exts: {
      style: '.wxss',
      template: '.wxml',
      filter: '.wxs'
    },
    vue: mpvueRuntime,
    compiler: mpvueCompiler,
    megalo: false,
    filterTag: 'wxs',
    subPackages: true,
    cssVars: {
      '--status-bar-height': '25px',
      '--window-top': '0px',
      '--window-bottom': '0px'
    },
    project: 'project.config.json',
    copyWebpackOptions ({
      assetsDir,
      manifestPlatformOptions
    }) {
      const files = [
        'sitemap.json',
        'ext.json',
        'custom-tab-bar'
      ]
      if (manifestPlatformOptions.workers) {
        files.push(manifestPlatformOptions.workers)
      }
      return [
        ...getStaticCopyOptions(assetsDir),
        ...getCopyOptions(['wxcomponents']),
        ...getCopyOptions(files, {}, false)
      ]
    }
  },
  'mp-baidu': {
    global: 'swan',
    exts: {
      style: '.css',
      template: '.swan',
      filter: '.filter.js'
    },
    vue: megaloRuntime,
    compiler: megaloCompiler,
    megalo: 'swan',
    filterTag: 'filter',
    subPackages: true,
    cssVars: {
      '--status-bar-height': '25px',
      '--window-top': '0px',
      '--window-bottom': '0px'
    },
    project: 'project.swan.json',
    copyWebpackOptions ({
      assetsDir
    }) {
      return [
        ...getStaticCopyOptions(assetsDir),
        ...getCopyOptions(['swancomponents'])
      ]
    }
  },
  'mp-alipay': {
    global: 'my',
    exts: {
      style: '.acss',
      template: '.axml',
      filter: '.sjs'
    },
    vue: megaloRuntime,
    compiler: megaloCompiler,
    megalo: 'alipay',
    filterTag: 'sjs',
    subPackages: true,
    cssVars: {
      '--status-bar-height': '25px',
      '--window-top': '0px',
      '--window-bottom': '0px'
    },
    copyWebpackOptions ({
      assetsDir
    }) {
      return [
        ...getStaticCopyOptions(assetsDir),
        ...getCopyOptions(['mycomponents'])
      ]
    }
  },
  'mp-toutiao': {
    global: 'tt',
    exts: {
      style: '.ttss',
      template: '.ttml'
    },
    vue: megaloRuntime,
    compiler: megaloCompiler,
    megalo: 'tt',
    subPackages: false,
    cssVars: {
      '--status-bar-height': '25px',
      '--window-top': '0px',
      '--window-bottom': '0px'
    },
    project: 'project.tt.json',
    copyWebpackOptions ({
      assetsDir
    }) {
      return [
        ...getStaticCopyOptions(assetsDir),
        ...getCopyOptions(['ttcomponents'])
      ]
    }
  }
}
// 解决 vue-cli-service lint 时 UNI_PLATFORM 不存在
process.env.UNI_PLATFORM = process.env.UNI_PLATFORM || 'h5'

const platform = PLATFORMS[process.env.UNI_PLATFORM]

const preprocessContext = {}

Object.keys(PLATFORMS).forEach(platform => {
  preprocessContext[platform.toUpperCase()] = false
})

preprocessContext[process.env.UNI_PLATFORM.toUpperCase()] = true

preprocessContext['MP'] = false
preprocessContext['APP'] = false
preprocessContext['APP-PLUS-NVUE'] = false
preprocessContext['APP_PLUS_NVUE'] = false

preprocessContext['APP-VUE'] = false
preprocessContext['APP_VUE'] = false
preprocessContext['APP-NVUE'] = false
preprocessContext['APP_NVUE'] = false

if (process.env.UNI_PLATFORM === 'app-plus') {
  preprocessContext['APP-VUE'] = true
  preprocessContext['APP_VUE'] = true
}

if (process.env.UNI_PLATFORM.indexOf('mp-') === 0) {
  preprocessContext['MP'] = true
}

if (process.env.UNI_PLATFORM.indexOf('app-') === 0) {
  preprocessContext['APP'] = true
}

if (process.UNI_SCRIPT_DEFINE && Object.keys(process.UNI_SCRIPT_DEFINE).length) {
  Object.keys(process.UNI_SCRIPT_DEFINE).forEach(name => {
    preprocessContext[name] = process.UNI_SCRIPT_DEFINE[name]
  })
}

Object.keys(preprocessContext).forEach(platform => {
  if (platform.indexOf('-') !== -1) {
    preprocessContext[platform.replace(/-/g, '_')] = preprocessContext[platform]
  }
})

const nvuePreprocessContext = Object.assign({}, preprocessContext, {
  'APP-VUE': false,
  'APP_VUE': false,
  'APP-NVUE': true,
  'APP_NVUE': true,
  'APP-PLUS-NVUE': true,
  'APP_PLUS_NVUE': true
})

const isInHBuilderX = fs.existsSync(path.resolve(process.env.UNI_CLI_CONTEXT, 'bin/uniapp-cli.js'))

let isInHBuilderXAlpha = false

if (isInHBuilderX) {
  try {
    if (require(path.resolve(process.env.UNI_CLI_CONTEXT, '../about/package.json')).alpha) {
      isInHBuilderXAlpha = true
    }
  } catch (e) {

  }
}

let sourceRoot = false

function devtoolModuleFilenameTemplate (info) {
  if (!sourceRoot) {
    if (isInHBuilderX) {
      sourceRoot = normalizePath(process.env.UNI_INPUT_DIR)
    } else {
      sourceRoot = normalizePath(process.env.UNI_CLI_CONTEXT)
    }
  }
  let filePath = false
  const absoluteResourcePath = normalizePath(info.absoluteResourcePath)
  if (
    absoluteResourcePath.indexOf(sourceRoot) !== -1 &&
    (
      absoluteResourcePath.endsWith('.js') ||
      absoluteResourcePath.endsWith('.ts')
    )
  ) {
    filePath = normalizePath(path.relative(sourceRoot, absoluteResourcePath))
    if (
      filePath.indexOf('node_modules/@dcloudio') === 0 ||
      filePath.indexOf('node_modules/vue-loader') === 0 ||
      filePath.indexOf('node_modules/webpack') === 0
    ) {
      filePath = false
    }
  } else if (
    !info.moduleId &&
    (
      absoluteResourcePath.endsWith('.vue') ||
      absoluteResourcePath.endsWith('.nvue')
    )
  ) {
    if (
      absoluteResourcePath.indexOf('src') !== 0 &&
      absoluteResourcePath.indexOf('node-modules') !== 0
    ) {
      filePath = normalizePath(path.relative(sourceRoot, absoluteResourcePath))
    } else {
      filePath = absoluteResourcePath
    }
  }
  if (
    filePath &&
    filePath !== 'main.js' &&
    filePath !== 'main.ts' &&
    filePath !== 'src/main.js' &&
    filePath !== 'src/main.ts'
  ) {
    return `uni-app:///${filePath}`
  }
}

const NODE_MODULES_REGEX = /(\.\.\/)?node_modules/g

function normalizeNodeModules (str) {
  str = str.replace(NODE_MODULES_REGEX, 'node-modules')
  if (process.env.UNI_PLATFORM === 'mp-alipay') {
    str = str.replace('node-modules/@', 'node-modules/npm-scope-')
  }
  return str
}

module.exports = {
  normalizeNodeModules,
  isInHBuilderX,
  isInHBuilderXAlpha,
  runByHBuilderX: isInHBuilderX || fs.existsSync(path.resolve(process.env.UNI_HBUILDERX_PLUGINS || '', 'weapp-tools')),
  devtoolModuleFilenameTemplate,
  getFlexDirection (json) {
    let flexDir = 'column'
    if (json && json['nvue'] && json['nvue']['flex-direction']) {
      flexDir = json['nvue']['flex-direction']
      const flexDirs = ['row', 'row-reverse', 'column', 'column-reverse']
      if (flexDirs.indexOf(flexDir) === -1) {
        flexDir = 'column'
      }
    }
    return flexDir
  },
  jsPreprocessOptions: {
    type: 'js',
    context: preprocessContext
  },
  cssPreprocessOptions: {
    type: 'css',
    context: preprocessContext
  },
  htmlPreprocessOptions: {
    type: 'html',
    context: preprocessContext
  },
  nvueCssPreprocessOptions: {
    type: 'css',
    context: nvuePreprocessContext
  },
  nvueJsPreprocessOptions: {
    type: 'js',
    context: nvuePreprocessContext
  },
  nvueHtmlPreprocessOptions: {
    type: 'html',
    context: nvuePreprocessContext
  },
  isSupportSubPackages () {
    return platform.subPackages
  },
  getPlatforms () {
    return Object.keys(PLATFORMS)
  },
  getPlatformCopy () {
    return platform.copyWebpackOptions
  },
  getPlatformGlobal () {
    return platform.global
  },
  getPlatformExts () {
    return platform.exts
  },
  getPlatformTarget () {
    return platform.megalo
  },
  getPlatformProject () {
    return platform.project
  },
  getPlatformFilterTag () {
    return platform.filterTag
  },
  getPlatformVue (vueOptions) {
    if (process.env.UNI_PLATFORM === 'h5' && vueOptions && vueOptions.runtimeCompiler) {
      return '@dcloudio/vue-cli-plugin-uni/packages/h5-vue/dist/vue.esm.js'
    }
    if (process.env.UNI_PLATFORM === 'app-plus' && process.env.UNI_USING_V3) {
      return '@dcloudio/uni-app-plus/dist/service.runtime.esm.js'
    }
    if (process.env.UNI_USING_COMPONENTS) {
      return uniRuntime
    }
    return platform.vue
  },
  getPlatformCompiler () {
    if (process.env.UNI_USING_COMPONENTS || process.env.UNI_PLATFORM === 'h5') {
      return require(uniCompiler)
    }
    return require(platform.compiler)
  },
  getPlatformCssVars () {
    return platform.cssVars
  },
  getPlatformCssnano () {
    return {
      calc: false,
      orderedValues: false,
      mergeLonghand: false,
      mergeRules: false,
      cssDeclarationSorter: false,
      discardComments: false,
      discardDuplicates: false // 条件编译会导致重复
    }
  },
  getShadowCss,
  getShadowTemplate (colorType = 'grey') {
    let tagName = 'cover-image'
    if (process.env.UNI_PLATFORM === 'mp-toutiao') {
      tagName = 'image'
    }
    return `<${tagName} src="https://cdn.dcloud.net.cn/img/shadow-${colorType}.png" style="z-index:998;position:fixed;left:0;top:0;width:100%;height:3px;"/>`
  },
  getPlatformScss () {
    return SCSS
  },
  getPlatformSass () {
    return SASS
  }
}
