/*
 * @Description: mock数据方法
 * @Author: smileswlin
 * @LastEditor: smileswlin
 * @Date: 020-05-24 21:16:49
 * @LastEditTime: 2022-02-22 17:33:24
 */
const path = require('path');
const fs = require('fs'); // 引入文件系统模块
const Mock = require('mockjs'); // mockjs 导入依赖模块
// const { file } = require('@gtff/tdesign-gt-vue/icon/icon-map');

/**
 * 读取json文件
 * @param filePath
 * @returns {any}
 */
function getMockFile(filePath) {
  // 读取指定json文件
  const json = fs.readFileSync(filePath, 'utf-8');
  // 解析并返回
  return JSON.parse(json);
}

/**
 * 读取文件夹下所有文件名并替换为路由模式字符串 eg: user_bulk__delete.json => /user/bulk_delete
 * @param jsonPath
 * @returns {{}}
 */
function getMockRouter(jsonPath) {
  const jsonFiles = [];
  try {
    // 检查传入目录是否存在
    fs.accessSync(jsonPath);

    const files = fs.readdirSync(jsonPath);

    files.forEach((item) => {
      let fileName = item;
      fileName = `/${item.replace(/_/g, '/').replace('.json', '')}`;
      fileName = fileName.replace(/\/\//g, '_'); // 若出现‘//’ ， 则改为_
      jsonFiles.push(fileName);
    });
  } catch (e) {
    console.log('error', e);
  }
  return jsonFiles;
}

/**
 * @description: 设置mock数据路由, 对应目录下，创建get或者post目录，该目录下的文件则为url请求地址 eg: user_bulk__delete.json => /user/bulk_delete
 * @param app {Object} app对象
 * @param method {String} 请求方式，get或者post
 * @param urlPrefix {String} url的前缀
 * @param dirPath {String} 对应的目录
 * @return: undefined
 */
exports.setMock = function (app, method, urlPrefix, dirPath) {
  const newDirPath = dirPath || path.join(process.cwd(), 'mock', method);
  getMockRouter(newDirPath).forEach((item) => {
    app[method](`${urlPrefix}${item}`, (req, res) => {
      // 每次响应请求时读取mock data的json文件
      // util.getMockFile方法定义了如何读取json文件并解析成数据对象
      const jsonPath = path.resolve(newDirPath, `${item.substr(1).replace(/_/g, '__').replace(/\//g, '_')}.json`);
      const json = getMockFile(jsonPath);
      res[method === 'get' ? 'json' : 'send'](Mock.mock(json)); // 将json传入 Mock.mock 方法中，生成的数据返回给浏览器
    });
  });
};

/**
 * @description: 已知当前目录，输出目录下所有文件信息（文件地址，文件名）
 * @param rootDir {String} 当前目录
 * @param files {Array} 目录下的文件
 * 1. 输入根目录，默认目录下文件为空
 * 2. 向下读取文件
 * 3. 判断是否是文件
 *    如果是合法文件，添加
 *    如果是目录，回到到第2步
 *    如果读取为空
 */
const formattedFiles = (rootDir, files = []) => {
  const childFiles = fs.readdirSync(rootDir);
  if (childFiles && childFiles.length && childFiles.length > 0) {
    // eslint-disable-next-line consistent-return
    childFiles.forEach((f) => {
      const url = path.join(rootDir, f);
      const isFile = fs.statSync(url).isFile();
      if (isFile) {
        // 判断文件是否 .DS_Store
        const isValid = f !== '.DS_Store';
        const ele = {
          jsonPath: url,
          pathName: url.replace('.json', ''),
          fileName: f,
        };
        isValid && files.push(ele);
      } else {
        return formattedFiles(url, files);
      }
    });
  }
  return files;
};

/**
 * @description: 设置mock数据路由, 对应目录下，创建get或者post目录，再请求目录下创建业务目录demo(没有层级层级的限制)，该目录下的文件则为url请求地址 eg: fail.json => /demo/fail
 * @param app {Object} app对象
 * @param method {String} 请求方式，get或者post
 * @param urlPrefix {String} url的前缀
 * @param dirPath {String} 对应的目录
 * @return: undefined
 */
exports.setMockByBasePath = (app, method, urlPrefix, dirPath) => {
  // 读取到根目录
  const rootDir = dirPath || path.join(process.cwd(), 'mock', method);
  const files = formattedFiles(rootDir).map((f) => {
    // eslint-disable-next-line no-param-reassign
    f.pathName = f.pathName.replace(rootDir, '').replace(/\\/g, '/');
    return f;
  });
  files.forEach(({ pathName, jsonPath }) => {
    app[method](`${urlPrefix}${pathName}`, (req, res) => {
      // 每次响应请求时读取mock data的json文件
      // util.getMockFile方法定义了如何读取json文件并解析成数据对象
      const json = getMockFile(jsonPath);
      res[method === 'get' ? 'json' : 'send'](Mock.mock(json)); // 将json传入 Mock.mock 方法中，生成的数据返回给浏览器
    });
  });
};

/**
 * @description: 设置mock数据路由, 增加子目录，mock/xxx/post 目录下的文件为url请求地址  eg: user_bulk__delete.json => /xxx/abc/user/bulk_delete
 * @param app {Object} app对象
 * @param methods {Array} 请求方式，,eg: ['get', 'post']
 * @param urlPrefix {String} url的前缀
 * @return: undefined
 */
exports.mockSubDirs = function (app, methods, urlPrefix) {
  const rootDirPath = path.join(process.cwd(), 'mock');

  const files = fs.readdirSync(rootDirPath);
  const dirs = files.filter((item) => fs.lstatSync(path.resolve(rootDirPath, item)).isDirectory());

  dirs.forEach((dir) => {
    const subUrlPrefix = dir.replace(/(?:[^_])_(?:[^_])/g, '/').replace(/__/g, '_');

    const dirPath = path.join(process.cwd(), 'mock', dir);
    methods.forEach((method) => {
      const rootUrlPrefix = urlPrefix[urlPrefix.length] === '/' ? urlPrefix.slice(0, -1) : urlPrefix;
      const urlPrefixResult = `${rootUrlPrefix}${subUrlPrefix}`;
      const dirPathResult = `${dirPath}/${method}`;
      console.log('mock with method:', method, ' urlPrefix:', urlPrefixResult, ' dir:', dirPathResult);
      exports.setMock(app, method, urlPrefixResult, dirPathResult);
    });
  });
};
