"use strict";

/* modified from NormalModuleReplacementPlugin */

const path = require("path");
const fs = require("fs")
const os = require("os")
const {execSync}= require('child_process')

const NANOAPP_INDEX = "nanoapp.index"
const PLUGIN_NAME = "nanoapp-plugin"


function getAppName(dir) {
  return JSON.parse(fs.readFileSync(path.join(dir, NANOAPP_INDEX)))["name"]
}


function createTmpDir() {
  const tmpDir = os.tmpdir()
  return fs.mkdtempSync(`${tmpDir}${path.sep}`)
}

class NanoappPlugin {
  constructor(nanoApps) {
    this.nanoApps = nanoApps
    this.tmp = createTmpDir()
    this.appResolves = {}
    this.ignoreDirs = {} // 检测过的就直接忽略掉
  }

  getAppIndexFile(rootDir, result) {
    // 回溯路径， 找到可能含有nanoapp index文件的路径
    let file
    if(!result.request.startsWith(path.sep)) {
      file = path.resolve(result.context, result.request)
    } else {
      file = result.request
    }

    if (!file.startsWith(rootDir)) return

    let matched
    while(file != rootDir) {
      file = file.replace(/\/[^\/]*\/?$/, "")
      if (this.ignoreDirs[file]) {
        continue
      }
      if (this.appResolves[file] || fs.existsSync(path.join(file, NANOAPP_INDEX))) {
        matched = file
        break
      } else {
        this.ignoreDirs[file] = true
      }
    }
    return matched
  }

  runNCG(dir) {
    if (this.appResolves[dir]) return
    this.logger.info(`start build nanoapp in ${dir}`)
    const targetDir = path.resolve(this.tmp, getAppName(dir))
    execSync(`npx nanoapp-ncg -out ${targetDir} -rel false`, {cwd: dir})
    this.appResolves[dir] = targetDir
    this.logger.debug("build finish " + targetDir)
  }

  apply(compiler) {
    this.logger = compiler.getInfrastructureLogger(PLUGIN_NAME)
    compiler.hooks.normalModuleFactory.tap(
      PLUGIN_NAME,
      nmf => {
        // 替换包含 nanoapp.index 路径为生成的临时路径
        nmf.hooks.beforeResolve.tap(PLUGIN_NAME, result => {
          if (!result) return;
          const indexDir = this.getAppIndexFile(compiler.context, result)
          if (indexDir) {
            this.runNCG(indexDir)
            result.request = path.resolve(result.context, result.request)
              .replace(indexDir, this.appResolves[indexDir])
          }
          return result;
        });
      }
    );
  }
}

module.exports = NanoappPlugin;
