const fs = require("fs");
const ejs = require("ejs");
const got = require("got");
const path = require("path");
const BASE_FILE_PATH = "/src/services/modules";
const TEMPLATE_FILE_PATH = "/template";
const API_EJS = "/template/apis/index.ejs";
const copyExt = [".js", ".ejs"];
const MODULE_TEMPLATE = path.join(__dirname, TEMPLATE_FILE_PATH);
const PROJECT_TEMPLATE = path.join(process.cwd(), TEMPLATE_FILE_PATH);
const METHODS_ARR = [
  "GET",
  "POST",
  "PUT",
  "DELETE",
  "PATCH",
  "COPY",
  "HEAD",
  "OPTIONS",
  "LINK",
  "UNLIK",
  "PURGE",
  "LOCK",
  "UNLOCK",
  "PROPFIND",
];
// function getSwaggerUrl() {
//     const url = process.argv.find((item) => item.includes('http')) || ''
//     return url.match(/http.*/g) ? url.match(/http.*/g)[0] : ''
// }
let pathKeys, paths;
async function getSwaggerJSON(swaggerUrl) {
  if (!swaggerUrl) {
    throw new Error("\x1B[31mSwagger地址不合理或不存在\x1B[0m");
  }
  const res = await got(swaggerUrl, {
    headers: {},
    responseType: "json",
  });
  return res.body;
}
async function go(swaggerUrl) {
  try {
    const swaggerJson = await getSwaggerJSON(swaggerUrl);
    generate(swaggerJson);
    console.log("\x1B[32m---执行完毕---");
  } catch (e) {
    console.log("\x1B[31mSwagger生成失败\x1B", e);
  }
}

function writeApiFile(mapPath) {
  for (let [key, value] of mapPath) {
    ejs.renderFile(
      path.join(process.cwd(), API_EJS),
      { infos: value },
      {},
      function (err, str) {
        if (err) {
          console.log(`\x1B[31m${err}\x1B`);
          return;
        }
        fs.writeFileSync(
          `${path.join(process.cwd(), BASE_FILE_PATH)}/${key}.js`,
          str
        );
      }
    );
  }
  // 生成index文件
  fs.copyFileSync(
    path.join(__dirname, `${TEMPLATE_FILE_PATH}/page/index.js`),
    path.join(process.cwd(), "src/services/index.js")
  );
}

function mkdirsSync(pathname) {
  if (fs.existsSync(pathname)) {
    return true;
  } else {
    if (mkdirsSync(path.dirname(pathname))) {
      fs.mkdirSync(pathname);
      return true;
    }
  }
}
let i = 0;

/**
 * 判断数组中的元素是否包含此字符串
 * @param arr
 * @param obj
 * @returns {boolean}
 */
const contains = function (arr, obj) {
  let flag = false;
  arr.map((val) => {
    if (obj.includes(val)) {
      flag = true;
    }
  });
  return flag;
};
/**
 * 在复制目录前需要判断该目录是否存在，
 * 不存在需要先创建目录
 * @param src
 * @param dst
 * @param callback
 */
const exists = function (src, dst, callback) {
  // 如果路径存在，则返回 true，否则返回 false。
  if (fs.existsSync(dst)) {
    callback(src, dst);
  } else {
    fs.mkdir(dst, function () {
      callback(src, dst);
    });
  }
};

const copyDir = function (src, dst) {
  // 读取目录中的所有文件/目录
  const pathArr = fs.readdirSync(src);
  pathArr.forEach(function (path) {
    const _src = src + "/" + path;
    const _dst = dst + "/" + path;
    let readable;
    let writable;
    fs.stat(_src, function (err, st) {
      if (err) {
        throw err;
      }

      // 判断是否为文件
      if (st.isFile()) {
        // 允许的后缀才可以被复制
        if (contains(copyExt, _src)) {
          if (fs.existsSync(_dst)) {
            goNext();
          } else {
            // 创建读取流
            readable = fs.createReadStream(_src);
            // 创建写入流
            writable = fs.createWriteStream(_dst);
            // 通过管道来传输流
            readable.pipe(writable);
            setTimeout(() => {
              goNext();
            }, 500);
          }
        } else {
          // console.log(_src + ' 不允许被复制!!!')
        }
      }
      // 如果是目录则递归调用自身
      else if (st.isDirectory()) {
        exists(_src, _dst, copyDir);
      }
    });
  });
};

// 在template创建之后进行services生成
function goNext() {
  const pathMap = new Map();
   pathKeys.forEach((uniKey) => {
    const uniKeyStr = uniKey.split("/");
    const moduleName = toCamel(uniKeyStr[1]);
    const name = uniKeyStr[uniKeyStr.length - 1];
    const interfaceData = paths[uniKey];
    // 一个接口中可能存在多个动词
    const methodsArr = METHODS_ARR.reduce((arr, method) => {
      const lowerCaseMethod = method.toLowerCase();
      if (typeof interfaceData[lowerCaseMethod] === "object") {
        arr.push({
          fullPath: uniKey,
          name,
          method: lowerCaseMethod,
          ...interfaceData[lowerCaseMethod],
        });
      }
      return arr;
    }, []);
    if (pathMap.has(moduleName)) {
      const existPath = pathMap.get(moduleName);
      pathMap.set(moduleName, [...existPath, ...methodsArr]);
    } else {
      pathMap.set(moduleName, methodsArr);
    }
  });
  writeApiFile(pathMap);
}

function generate({ paths: pathArr }) {
  paths = pathArr;
  pathKeys = Object.keys(paths);
  mkdirsSync(path.join(process.cwd(), BASE_FILE_PATH));
  const files = fs.readdirSync(path.join(process.cwd(), BASE_FILE_PATH));
  if (files.length) {
    // 如果services里面有文件，则不覆盖
    console.log(`\x1B[31mServices目录已存在内容，替换先删除\x1B`);
    return;
  }
  exists(MODULE_TEMPLATE, PROJECT_TEMPLATE, copyDir);
}
// 短横线转小驼峰
function toCamel(str) {
  return str.replace(
    /([^-])(?:-+([^-]))/g,
    ($0, $1, $2) => $1 + $2.toUpperCase()
  );
}

module.exports = go;
