const chalk = require('chalk');
const shell = require('shelljs');
const { revert } = require('./revert');
const path = require('path');
const fs = require('fs');
const { getAllFiles, getFile, getConfig, showTips } = require('./utils');
let i18nFile;
let config = {
  key: '',
  single: false,
  langFolder: ''
};
let generate = 1;

// messagesHash 存储 messages 的 value:key，用来判断是否有存在这个 value，有的话就不生成新 key，共用这个 key
let messagesHash = {};

let messages = {};

let rootPath;

// 有被替换过的文件需要进行 prettier 否则格式会有错误
let needPrettierFiles = [];
/**
 * 初始化当前存在的 message，后续生成的会进行合并
 */
const initMessage = () => {
  // 存在时，进行存储
  if (fs.existsSync(i18nFile)) {
    try {
      messages = require(i18nFile);

      Object.keys(messages).forEach(key => {
        messagesHash[messages[key]] = key;
      });

      // 获取最大的index
      // generate =
      //   Math.max(
      //     ...Object.keys(messages).map(item => item.replace(/^[^\d]+/, '') - 0)
      //   ) || 1;
    } catch (e) {}
  }
  if (!messages || !Object.keys(messages).length) {
    messages = {};
  }
};
/**
 * 写入国际化消息文件
 */
const writeMessage = () => {
  // TODO：需要看下怎么更新其他文件，en-us，zh-toLowerCase

  // 若设置了国际化文件目录，则同时更新所有的国际化文件
  // if (config.path) {
  //   try {
  //     let localeDir = path.join(process.cwd(), config.path ? config.path : '');
  //     fs.readdirSync(localeDir).forEach(file => {
  //       file = path.join(localeDir, file);
  //       if (file !== i18nFile) {
  //         let oldMessages = require(file);
  //         fs.writeFileSync(
  //           file,
  //           `module.exports = ${JSON.stringify(
  //             Object.assign({}, messages, oldMessages),
  //             null,
  //             '\t'
  //           )}`,
  //           'utf8'
  //         );
  //       }
  //     });
  //   } catch (e) {}
  // }
  fs.writeFileSync(
    i18nFile,
    `module.exports = ${JSON.stringify(messages, null, '\t')}`,
    'utf8'
  );

  console.log(
    chalk.green(
      `\n✨ generate success!\n${path.relative(process.cwd(), i18nFile)}\n`
    )
  );
  showTips();
};

// /**
//  * 获取key前缀
//  */
// const getPreKey = file => {
//   return config.key
//     ? `${config.key.replace(/[-_]+$/, '')}_`
//     : `${path
//         .relative(rootPath, file)
//         .replace(/[\\/\\\\-]/g, '_')
//         .replace(/\..*$/, '')}_`;
// };

/**
 * 获取当前key，使用中文当 key
 */
// const getCurrentKey = (match, file) => {
//   if (messagesHash[match]) return messagesHash[match];
//   let key = getPreKey(file) + generate++;
//   // if (!messages[key]) return key.toLowerCase();
//   if (!messages[key]) return match;
//   return getCurrentKey(match, file);
// };

/**
 * 中文 key 不需要考虑太多
 */
const getCurrentKey = (match, file) => {
  // value 是一样的话，直接返回
  if (messagesHash[match]) return messagesHash[match];
  return match;
};

const resetIndex = () => {
  // 对于支持单文件index情况，恢复初始index
  if (config.single && !config.key) {
    generate = 1;
  }
};

const resetMessageHash = () => {
  // 针对没有设置key的情况，恢复每次文件的messageHash
  if (!config.key) {
    messagesHash = {};
  }
};

/**
 * 替换 Vue 文件中的需要国际化的部分
 */
const generateVueFile = file => {
  let processFile = path.relative(process.cwd(), file);
  // console.log(`➤ ${processFile.yellow}`.blue);
  // console.log(`${chalk.blue('➤')} ${chalk.yellow(processFile)}`);

  resetIndex();
  resetMessageHash();

  // 标记这个文件是否被替换 i18n 标记是的话，才会执行覆盖 content
  let hasReplaced = false;
  let content = fs.readFileSync(file, 'utf8');

  // 替换template中的部分
  content = content.replace(/<template(.|\n|\r)*template>/gim, match => {
    // #region 这段是源库新增的，TODO:待理解，这段代码还没有命中场景
    match = match.replace(
      /(["'])`([^`\n\r]*[\u4e00-\u9fa5]+[^`\n\r]*)`(['"])/gim,
      (_, prev, match, after) => {
        match = match.trim();
        let matchIndex = 0;
        let matchArr = [];
        let result;
        match = match.replace(/(\${)([^{}]+)(})/gim, (_, prev, match) => {
          matchArr.push(match);
          return `{${matchIndex++}}`;
        });
        let currentKey = getCurrentKey(match, file);
        if (!matchArr.length) {
          result =
            prev === '"' ? `"$t('${currentKey}')"` : `'$t("${currentKey}")'`;
        } else {
          result =
            prev === '"'
              ? `"$t('${currentKey}', [${matchArr.toString()}])"`
              : `'$t("${currentKey}", [${matchArr.toString()}])'`;
        }
        messages[currentKey] = match;
        messagesHash[match] = currentKey;
        hasReplaced = true;
        return result;
      }
    );
    // #endregion

    return match.replace(
      // 源
      // /(\w+='|\w+="|>|'|")([^'"<>]*[\u4e00-\u9fa5]+[^'"<>]*)(['"<])/gim,

      // #region ✨ fix 正则匹配 \w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 没有中划线 和 点.。这里就不能匹配到使用连接符的组件属性
      /([-\w]+='|[-\w]+="|>|'|")([^'"<>]*[\u4e00-\u9fa5]+[^'"<>]*)(['"<])/gim,
      (_, prev, match, after) => {
        // #endregion

        // #region 暂时舍弃，还是先执行 revert 再 generate ✨ 新增，判断如果当前已经被生成，也就是有携带了 $t 标志，那就不需要再进行 generate
        /**
         * 前面的 ”：“主要是匹配有正则表达式存在时的冒号
         */
        // /([-\w]+='|[-\w]+="|>|'|"|:)([^'"<>]*(\$t\(['"].+?)?[\u4e00-\u9fa5]+[^'"<>]*)(['"<])/gim,
        // (_, prev, match, $tBegin, after) => {
        //   if ($tBegin) {
        //     // 直接返回拿来匹配的子串，不变
        //     return _;
        //   }
        // #endregion

        match = match.trim();
        let result = '';
        let currentKey;
        if (match.match(/{{[^{}]+}}/)) {
          // 对于 muscache 中部分的替换
          let matchIndex = 0;
          let matchArr = [];
          match = match.replace(/{{([^{}]+)}}/gim, (_, match) => {
            // matchArr.push(match);
            // ✨ 迎合 prettier
            matchArr.push(match.trim());
            return `{${matchIndex++}}`;
          });
          currentKey = getCurrentKey(match, file);
          if (!matchArr.length) {
            // result = `${prev}{{$t('${currentKey}')}}${after}`;
            // ✨ 迎合 prettier
            result = `${prev}{{ $t('${currentKey}') }}${after}`;
          } else {
            // result = `${prev}{{$t('${currentKey}', [${matchArr.toString()}])}}${after}`;
            // ✨ 迎合 prettier
            matchArr = matchArr.join(', ');
            result = `${prev}{{ $t('${currentKey}', [${matchArr.toString()}]) }}${after}`;
          }
        } else {
          currentKey = getCurrentKey(match, file);

          // if (prev.match(/^\w+='$/)) {
          // ✨ fix
          if (prev.match(/^[-\w]+='$/)) {
            // 对于属性中普通文本的替换
            result = `:${prev}$t("${currentKey}")${after}`;
          }
          // else if (prev.match(/^\w+="$/)) {
          // ✨ fix
          else if (prev.match(/^[-\w]+="$/)) {
            // 对于属性中普通文本的替换
            result = `:${prev}$t('${currentKey}')${after}`;
          } else if (prev === '"' || prev === "'") {
            // 对于属性中参数形式中的替换
            result = `$t(${prev}${currentKey}${after})`;
          } else {
            // 对于tag标签中的普通文本替换
            // result = `${prev}{{$t('${currentKey}')}}${after}`;
            // ✨ 迎合 prettier
            result = `${prev}{{ $t('${currentKey}') }}${after}`;
          }
        }

        messages[currentKey] = match;
        messagesHash[match] = currentKey;
        hasReplaced = true;
        return result;
      }
    );
  });
  // 替换script中的部分
  // content = content.replace(/<script(.|\n|\r)*script>/gim, match => {
  // ✨ 匹配 Vue3 setup 语法糖，tips：？非贪婪匹配
  content = content.replace(/<script.*setup.*>(.|\n)*?<\/script>/gim, match => {
    // 替换注释部分
    let comments = {};
    let commentsIndex = 0;

    // #region ✨ 判断是否已经引入了 vue-i18n
    const vuei18nMatch = match.match(
      /(import[\s\t]+.+[\s\t]+from[\s\t]+'vue-i18n'[\s\t]*;?)/m
    );
    if (!vuei18nMatch) {
      // const scriptSetupTop = match.match(/<script.*setup.*>/);
      const scriptSetupTop = match.match(/<script.*?setup.*?>/);
      match = match.replace(scriptSetupTop[0], $ => {
        return `${$}\nimport { useI18n } from 'vue-i18n';`;
      });
    }
    // 原
    // let imports = match.match(/from[\s\t]+['"][^'"]+['"][\s\t]*;?/gm);
    // fix:保证是最后一个 import
    let imports = match.match(/import .+ from[\s\t]+['"][^'"]+['"][\s\t]*;?/gm);
    let lastImport = imports[imports.length - 1];
    //  判断是否有 const { t: $t } = useI18n();
    if (!match.match(/const.+= useI18n\(\)/)) {
      match = match.replace(lastImport, $ => {
        return `${$}\nconst { t, t: $t } = useI18n();`;
      });
    }
    // #endregion

    match = match.replace(
      /(\/\*(.|\n|\r)*\*\/)|(\/\/.*)/gim,
      (match, p1, p2, p3, offset, str) => {
        // 排除掉url协议部分
        if (offset > 0 && str[offset - 1] === ':') return match;
        let commentsKey = `/*comment_${commentsIndex++}*/`;
        comments[commentsKey] = match;
        return commentsKey;
      }
    );

    match = match.replace(
      /(['"`])(((?!\1).)*[\u4e00-\u9fa5]+((?!\1).)*)\1/gim,
      (_, prev, match) => {
        match = match.trim();
        let currentKey;
        let result = '';
        if (prev !== '`') {
          // 对于普通字符串的替换
          currentKey = getCurrentKey(match, file);
          // result = `this.$t('${currentKey}')`;

          // ✨ Vue3 中没有 this 概念，使用 useI18n hook
          result = `$t('${currentKey}')`;
        } else {
          // 对于 `` 拼接字符串的替换
          let matchIndex = 0;
          let matchArr = [];
          match = match.replace(/(\${)([^{}]+)(})/gim, (_, prev, match) => {
            // matchArr.push(match);
            // ✨ 迎合 prettier
            matchArr.push(match.trim());
            return `{${matchIndex++}}`;
          });
          currentKey = getCurrentKey(match, file);
          if (!matchArr.length) {
            // result = `this.$t('${currentKey}')`;
            result = `$t('${currentKey}')`;
          } else {
            // result = `this.$t('${currentKey}', [${matchArr.toString()}])`;

            // ✨ 迎合 prettier
            matchArr = matchArr.join(', ');

            // ✨ 迎合 prettier，matchArr.toString().trim() 需要去掉空格
            result = `$t('${currentKey}', [${matchArr.toString()}])`;
          }
        }
        messages[currentKey] = match;
        messagesHash[match] = currentKey;
        hasReplaced = true;
        return result;
      }
    );

    // 换回注释
    return match.replace(/\/\*comment_\d+\*\//gim, match => {
      return comments[match];
    });
  });

  hasReplaced && fs.writeFileSync(file, content, 'utf-8');
  hasReplaced && needPrettierFiles.push(processFile);
  // console.log(`✔ ${processFile.yellow}`.green);
  // console.log(
  //   `${chalk.green('✔')} [G] ${chalk[hasReplaced ? 'green' : 'gray'](
  //     processFile
  //   )}`
  // );
  console.log(chalk[hasReplaced ? 'green' : 'gray'](`✔ [G] ${processFile}`));
};

// /**
//  * 替换普通 js 文件中的需要国际化的部分
//  */
// const generateJsFile = file => {
//   let processFile = path.relative(process.cwd(), file);
//   console.log(`➤ ${processFile.yellow}`.blue);
//   resetIndex();
//   resetMessageHash();
//   let hasReplaced = false;
//   let content = fs.readFileSync(file, 'utf8');
//   // 判断是否已经引入了 Vue， 若没有引入，则在文件头部引入
//   let vueMatch = content.match(
//     /(import[\s\t]+([^\s\t]+)[\s\t]+from[\s\t]+'vue'[\s\t]*;?)|((let|var|const)[\s\t]+([^\s\t]+)[\s\t]+\=[\s\t]+require\('vue'\)[\s\t]*;?)/m
//   );
//   let vueModule = 'Vue';
//   if (!vueMatch) {
//     content = `import Vue from 'vue';\n${content}`;
//   } else {
//     vueModule = vueMatch[2] || vueMatch[5];
//   }
//   let imports = content.match(/from[\s\t]+['"][^'"]+['"][\s\t]*;?/gm);
//   let lastImport = imports[imports.length - 1];
//   // 判断是否已经做过绑定 $t 的绑定，若没有，则自动绑定 $t
//   if (
//     !content.match(
//       /const[\s\t]+\$t[\s\t]+=[\s\t]+_i18n_vue.\$t.bind\(_i18n_vue\)[\s\t]*;?/
//     )
//   ) {
//     content = content.replace(lastImport, $ => {
//       return `${$}\nlet _i18n_vue = new ${vueModule}();\nconst $t = _i18n_vue.$t.bind(_i18n_vue);`;
//     });
//   }
//   // 替换注释部分
//   let comments = {};
//   let commentsIndex = 0;
//   content = content.replace(
//     /(\/\*(.|\n|\r)*\*\/)|(\/\/.*)/gim,
//     (match, p1, p2, p3, offset, str) => {
//       // 排除掉url协议部分
//       if (offset > 0 && str[offset - 1] === ':') return match;
//       let commentsKey = `/*comment_${commentsIndex++}*/`;
//       comments[commentsKey] = match;
//       return commentsKey;
//     }
//   );
//   content = content.replace(
//     /(['"`])(((?!\1).)*[\u4e00-\u9fa5]+((?!\1).)*)\1/gim,
//     (_, prev, match) => {
//       match = match.trim();
//       let currentKey;
//       let result = '';
//       if (prev !== '`') {
//         // 对于普通字符串的替换
//         currentKey = getCurrentKey(match, file);
//         result = `$t('${currentKey}')`;
//       } else {
//         // 对于 `` 拼接字符串的替换
//         let matchIndex = 0;
//         let matchArr = [];
//         match = match.replace(/(\${)([^{}]+)(})/gim, (_, prev, match) => {
//           matchArr.push(match);
//           return `{${matchIndex++}}`;
//         });
//         currentKey = getCurrentKey(match, file);
//         if (!matchArr.length) {
//           result = `$t('${currentKey}')`;
//         } else {
//           result = `$t('${currentKey}', [${matchArr.toString()}])`;
//         }
//       }
//       messages[currentKey] = match;
//       messagesHash[match] = currentKey;
//       hasReplaced = true;
//       return result;
//     }
//   );
//   // 换回注释部分
//   content = content.replace(/\/\*comment_\d+\*\//gim, match => {
//     return comments[match];
//   });
//   hasReplaced && fs.writeFileSync(file, content, 'utf-8');
//   console.log(`✔ ${processFile.yellow}`.green);
// };

/**
 * 替换普通 ts/js 文件中的需要国际化的部分
 * 兼容 vue3、vue-i18n for vue3
 */
const generateTsOrJsFile = file => {
  let processFile = path.relative(process.cwd(), file);
  // console.log(`➤ ${processFile.yellow}`.blue);
  // console.log(`${chalk.blue('➤')} ${chalk.yellow(processFile)}`);

  // resetIndex();
  resetMessageHash();
  let hasReplaced = false;
  let content = fs.readFileSync(file, 'utf8');

  // #region ✨ 判断是否已经引入了 @/locale
  const vuei18nMatch = content.match(
    /(import[\s\t]+.+[\s\t]+from[\s\t]+'@\/locale'[\s\t]*;?)/m
  );
  if (!vuei18nMatch) {
    content = `import i18n from '@/locale';\n${content}`;
  }

  // fix:保证是最后一个 import
  let imports = content.match(/import .+ from[\s\t]+['"][^'"]+['"][\s\t]*;?/gm);
  let lastImport = imports[imports.length - 1];
  // 判断是否有 const { t, t: $t } = i18n.global;
  if (!content.match(/const .+ = i18n\.global;/)) {
    content = content.replace(lastImport, $ => {
      return `${$}\nconst { t, t: $t } = i18n.global;`;
    });
  }
  // #endregion

  // 替换注释部分
  let comments = {};
  let commentsIndex = 0;
  content = content.replace(
    /(\/\*(.|\n|\r)*\*\/)|(\/\/.*)/gim,
    (match, p1, p2, p3, offset, str) => {
      // 排除掉url协议部分
      if (offset > 0 && str[offset - 1] === ':') return match;
      let commentsKey = `/*comment_${commentsIndex++}*/`;
      comments[commentsKey] = match;
      return commentsKey;
    }
  );
  content = content.replace(
    /(['"`])(((?!\1).)*[\u4e00-\u9fa5]+((?!\1).)*)\1/gim,
    (_, prev, match) => {
      match = match.trim();
      let currentKey;
      let result = '';
      if (prev !== '`') {
        // 对于普通字符串的替换
        currentKey = getCurrentKey(match, file);
        result = `$t('${currentKey}')`;
      } else {
        // 对于 `` 拼接字符串的替换
        let matchIndex = 0;
        let matchArr = [];
        match = match.replace(/(\${)([^{}]+)(})/gim, (_, prev, match) => {
          matchArr.push(match);
          return `{${matchIndex++}}`;
        });
        currentKey = getCurrentKey(match, file);
        if (!matchArr.length) {
          result = `$t('${currentKey}')`;
        } else {
          result = `$t('${currentKey}', [${matchArr.toString()}])`;
        }
      }
      messages[currentKey] = match;
      messagesHash[match] = currentKey;
      hasReplaced = true;
      return result;
    }
  );
  // 换回注释部分
  content = content.replace(/\/\*comment_\d+\*\//gim, match => {
    return comments[match];
  });
  hasReplaced && fs.writeFileSync(file, content, 'utf-8');
  hasReplaced && needPrettierFiles.push(processFile);
  // console.log(`✔ ${processFile.yellow}`.green);
  // console.log(`${chalk.green('✔')} ${chalk.yellow(processFile)}`);
  // console.log(
  //   `${chalk.green('✔')} [G] ${chalk[hasReplaced ? 'green' : 'gray'](
  //     processFile
  //   )}`
  // );
  console.log(chalk[hasReplaced ? 'green' : 'gray'](`✔ [G] ${processFile}`));
};

/**
 * generate 之前先执行一次 revert ，否则会导致重复嵌套 $($(...))
 *
 * src 可以是一个文件夹，也可以只是一个文件
 */
module.exports.generate = (src, langFolder, options) => {
  config = Object.assign(config, { langFolder }, options);
  rootPath = path.join(process.cwd(), src);
  let i18nPath = path.join(process.cwd(), langFolder ? langFolder : '');
  i18nFile = path.join(i18nPath, `${options.fileName}.js`);

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

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

  // // ✨ 有文件的情况下 && message 不为空， 才进行 revert
  // if (fs.existsSync(i18nFile)) {
  //   const obj = require(i18nFile);
  //   if (Object.keys(obj).length > 0) {
  //     // tips:执行一次revert，这里需要显式传递参数，使用命令的话有默认值，
  //     revert(src, langFolder, { fileName: options.fileName });
  //   }
  // }

  // 直接 revert ，revert 的机制已经更改，不管有没有 zh_CN.js 文件
  revert(src, langFolder, { fileName: options.fileName }, { generate: true });

  // exect=true 去除冗余 key
  if (!options.exect) {
    // 初始化
    initMessage();
  }

  // 操作
  files.forEach(item => {
    if (
      item !== i18nFile &&
      (!config || (config.langFolder && item.indexOf(i18nPath) < 0))
    ) {
      path.extname(item).toLowerCase() === '.vue'
        ? generateVueFile(item)
        : generateTsOrJsFile(item);
    }
  });

  // 重新写入本地文件
  writeMessage();

  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')
        );
      }
    }
  );
};
