const path = require('path');
const shell = require('shelljs');
const fs = require('fs');
const { getAllFiles, getFile, showTips, getConfig } = require('./utils');
const chalk = require('chalk');
let i18nFile;
let messages = {};
let rootPath;
let rootNode = '';

// 有被替换过的文件需要进行 prettier 否则格式会有错误
let needPrettierFiles = [];

/**
 * 舍弃：revert 不再依赖 message
 */
const initMessage = () => {
  try {
    messages = require(i18nFile);
  } catch (e) {
    console.error(
      chalk.red(
        `✖️ [R] 国际化资源文件错误或不存在，\n${path.relative(
          process.cwd(),
          i18nFile
        )}\n请确认后重试（注意，国际化文件不要使用 ES Module）\nor 如果当前项目已经被 generate ，请找回这个国际化文件，因为这个文件是执行 revert 的基础！\nor 如果当前项目没有被 generate 过，执行 generate 命令即可！`
      )
    );
    process.exit(0);
  }
};

// ❌ bug
// const getMessage = key => {
//   try {
//     key = key.split('.');
//     let message = messages;
//     key.forEach(item => {
//       message = message[item];
//     });
//     return message;
//   } catch (e) {
//     console.error(
//       chalk.red(`KEY: ${key} 查找国际化资源失败，请查证后继续执行代码`)
//     );
//     process.exit(0);
//   }
// };

/**
 * ✨ fix:目前都采用一级key，不要考虑多级。
 * 旧代码逻辑如果有存在可以中带有”.“，这里就会返回 undefined
 *
 */
const getMessage = (key, processFile) => {
  // 现在的 zh_CN.js 文件 key 和 value 是一致的，所以这里也可以直接返回 key，就不会存在有什么错误了
  return key;

  // try {
  //   if (messages[key]) {
  //     return messages[key] || key;
  //   } else {
  //     throw new Error();
  //   }
  // } catch (e) {
  //   console.error(
  //     chalk.red(
  //       `✖️ [R] KEY: "${key}"，查找失败\n${processFile}\n请查证后继续执行代码\nor 手动拆掉外层 $t()，重新执行\n`
  //     )
  //   );
  //   process.exit(0);
  // }
};

const converParamsMessage = (params, message) => {
  params = params.replace(/]$/, '').split(',');
  // ✨ 迎合 prettier
  params = params.map(_ => _.trim());
  return (
    '`' +
    message.replace(/{[\s\t]*(\d)[\s\t]*}/gim, (_, match) => {
      return '${' + params[match - 0] + '}';
    }) +
    '`'
  );
};

const converParamsMessageForTemplateMuscache = (params, message) => {
  params = params.replace(/]$/, '').split(',');
  // ✨ 迎合 prettier
  params = params.map(_ => _.trim());
  return message.replace(/{[\s\t]*(\d)[\s\t]*}/gim, (_, match) => {
    return `{{ ${params[match - 0]} }}`;
  });
};

const revertVueFile = file => {
  let processFile = path.relative(process.cwd(), file);

  // 标记这个文件是否会被替换，才会执行覆盖 content
  let hasReplaced = false;

  // console.log(`➤ ${processFile.yellow}`.blue);
  let content = fs.readFileSync(file, 'utf8');
  // 替换template中的部分
  content = content.replace(/<template(.|\n)*template>/gim, match => {
    let result = match.replace(
      // 源
      // /{{(this\.)?\$t\(([^{}]+)\)}}/gim,
      // ✨ 迎合 prettier
      /{{ (this\.)?\$t\(([^{}]+)\) }}/gim,
      (_, _this, match) => {
        match = match
          .replace(/^\$t\(/, '')
          .replace(/\)$/, '')
          .split(/,[\s\t]*[\[{]/);
        let key = match[0].trim().replace(/['"]/g, '');
        key = rootNode ? `${rootNode}.${key}` : key;

        let message = getMessage(key, processFile);
        if (match.length > 1) {
          // 源
          // return `{{${converParamsMessage(match[1].trim(), message)}}`;
          // ✨ 修复源库 bug
          // return `{{${converParamsMessage(match[1].trim(), message)}}}`;
          // ✨ 迎合 prettier
          return `{{ ${converParamsMessage(match[1].trim(), message)} }}`;
        }

        hasReplaced = true;
        return message;
      }
    );

    // #region ✨ fix:针对 template 中有参数的场景恢复
    /**
     * generate:
     * <div>{{ $t('您好 {0} {1}', [t1, t2]) }}</div>
     *
     * revert:
     * <div>您好 {{ t1 }} {{ t2 }}</div>
     */
    result = result.replace(/{{ \$t\(([^()]+)\) }}/gim, (_, match) => {
      match = match.split(/,[\s\t]*[\[{]/);
      let key = match[0].trim().replace(/['"]/g, '');
      key = rootNode ? `${rootNode}.${key}` : key;
      let message = getMessage(key, processFile);
      const res = converParamsMessageForTemplateMuscache(
        match[1].trim(),
        message
      );
      hasReplaced = true;
      return res;
    });
    // #endregion

    return result.replace(
      /(:[^'"]+['"])(this\.)?\$t\(([^()]+)\)(['"])/gim,
      (_, prev, _this, match, after) => {
        match = match.split(/,[\s\t]*[\[{]/);
        let key = match[0].trim().replace(/['"]/g, '');
        key = rootNode ? `${rootNode}.${key}` : key;
        let message = getMessage(key, processFile);
        if (match.length > 1) {
          return `${prev}{{${converParamsMessage(
            match[1].trim(),
            message
          )}}}${after}`;
        }
        hasReplaced = true;
        return `${prev.replace(/^:/, '')}${message}${after}`;
      }
    );
  });
  // 替换script中的部分
  // content = content.replace(/<script (.|\n)*script>/gim, match => {
  // ✨ 匹配 Vue3 setup 语法糖，tips：？非贪婪匹配
  content = content.replace(/<script.*setup.*>(.|\n)*?<\/script>/gim, match => {
    return match.replace(/\$t\(([^()]+)\)/gim, (_, match) => {
      match = match.split(/,[\s\t]*[\[{]/);
      let key = match[0].trim().replace(/['"]/g, '');
      key = rootNode ? `${rootNode}.${key}` : key;

      let message = getMessage(key, processFile);
      if (match.length > 1) {
        return converParamsMessage(match[1].trim(), message);
      }
      hasReplaced = true;
      return `'${message}'`;
    });
  });
  hasReplaced && fs.writeFileSync(file, content, 'utf-8');
  hasReplaced && needPrettierFiles.push(processFile);

  // console.log(chalk.green(`✔ ${processFile}`));
  console.log(chalk[hasReplaced ? 'green' : 'gray'](`✔ [R] ${processFile}`));
};
const revertTsOrJsFile = file => {
  let processFile = path.relative(process.cwd(), file);
  // console.log(`➤ ${processFile.yellow}`.blue);

  let hasReplaced = false;
  let content = fs.readFileSync(file, 'utf8');
  content = content.replace(
    /(this\.)?\$t\(([^()]+)\)/gim,
    (_, _this, match) => {
      match = match.split(/,[\s\t]*[\[{]/);
      let key = match[0].trim().replace(/['"]/g, '');
      key = rootNode ? `${rootNode}.${key}` : key;
      let message = getMessage(key, processFile);
      if (match.length > 1) {
        return converParamsMessage(match[1].trim(), message);
      }
      hasReplaced = true;
      return `'${message}'`;
    }
  );
  hasReplaced && fs.writeFileSync(file, content, 'utf-8');
  hasReplaced && needPrettierFiles.push(processFile);

  // console.log(chalk.green(`✔ ${processFile}`));
  console.log(chalk[hasReplaced ? 'green' : 'gray'](`✔ [R] ${processFile}`));
};

module.exports.revert = (src, langFolder, options, ext) => {
  rootPath = path.join(process.cwd(), src);
  i18nFile = path.join(
    process.cwd(),
    langFolder ? langFolder : '',
    `${options.fileName}.js`
  );
  if (options.rootnode) {
    rootNode = options.rootnode;
  }

  // initMessage();

  // 先初始化配置文件
  getConfig();

  // let files = getAllFiles(rootPath);
  let files = [];
  // 判断 src 是文件还是文件夹
  if (fs.lstatSync(rootPath).isDirectory()) {
    files = getAllFiles(rootPath);
  } else {
    files = getFile([rootPath]);
  }

  files.forEach(item => {
    if (item !== i18nFile) {
      path.extname(item).toLowerCase() === '.vue'
        ? revertVueFile(item)
        : revertTsOrJsFile(item);
    }
  });

  console.log(chalk.green(`\n✨ revert success!\n`));

  // 判断当前是否是在执行生成，是的话不执行以下代码
  if (!(ext && ext.generate)) {
    showTips();
    needPrettierFiles.push('src/locale/lang');
    needPrettierFiles = needPrettierFiles.map(
      item => `${path.relative(process.cwd(), item)}`
    );
    // 调用 prettier 格式化
    shell.exec(
      `prettier --write ${needPrettierFiles.join(' ')}`,
      (code, stdout, stderr) => {
        if (code === 0) {
          console.log(chalk.green('\n✨ prettier 格式化成功'));
        } else {
          console.log(
            chalk.red('prettier 格式化失败，请检查是否有安装 prettier')
          );
        }
      }
    );
  }
};
