/**
 * 提取代码块内容，支持未闭合的代码块，排除指定语言
 */
function preprocessCodeBlocks(text, excludedLanguages = []) {
  let protectedText = text;
  const codeBlockPlaceholders = [];
  const inlineCodePlaceholders = [];

  // 保护代码块（排除指定语言）
  protectedText = protectCodeBlocks(protectedText, codeBlockPlaceholders, excludedLanguages);

  // 保护行内代码
  protectedText = protectInlineCode(protectedText, inlineCodePlaceholders);
  return {
    protectedText,
    codeBlockPlaceholders,
    inlineCodePlaceholders
  };
}

/**
 * 保护代码块，替换为占位符（排除指定语言）
 */
function protectCodeBlocks(text, placeholders, excludedLanguages = []) {
  let protectedText = text;

  // 匹配围栏代码块（```），支持前面有空格或tab缩进
  const fencePattern = /^[ \t]*```([^\n]*)\n([\s\S]*?)\n[ \t]*```$/gm;
  protectedText = protectedText.replace(fencePattern, (match, lang) => {
    // 检查是否应该保护这个代码块
    if (shouldProtectCodeBlock(lang, excludedLanguages)) {
      const placeholder = `@@CODE_BLOCK_PLACEHOLDER_${placeholders.length}@@`;
      placeholders.push(match);
      return placeholder;
    }
    // 如果语言在排除列表中，不进行保护，让其他插件处理
    return match;
  });

  // 支持未闭合的代码块
  // 匹配未闭合的代码块（以```开始但没有结束的），支持前面有空格或tab缩进
  const unclosedPattern = /^[ \t]*```([^\n]*)\n([\s\S]+)$/gm;
  protectedText = protectedText.replace(unclosedPattern, (match, lang, code) => {
    // 检查是否真的是未闭合的（不以```结尾）
    if (!code.trim().endsWith('```') && shouldProtectCodeBlock(lang, excludedLanguages)) {
      const placeholder = `@@CODE_BLOCK_PLACEHOLDER_${placeholders.length}@@`;
      placeholders.push(match);
      return placeholder;
    }
    return match;
  });
  return protectedText;
}

/**
 * 判断是否应该保护代码块
 */
function shouldProtectCodeBlock(lang, excludedLanguages = []) {
  if (!lang) return true; // 无语言标识的代码块默认保护

  const normalizedLang = lang.toLowerCase().trim();
  return !excludedLanguages.some(excluded => excluded.toLowerCase() === normalizedLang);
}

/**
 * 保护行内代码，替换为占位符
 */
function protectInlineCode(text, placeholders) {
  // 匹配行内代码（`code`）
  const inlinePattern = /`([^`\n]+)`/g;
  return text.replace(inlinePattern, match => {
    const placeholder = `@@INLINE_CODE_PLACEHOLDER_${placeholders.length}@@`;
    placeholders.push(match);
    return placeholder;
  });
}

/**
 * 代码预处理钩子 - 处理代码保护的完整流程
 * 1. 将代码块替换为占位符进行保护（排除配置中指定的语言）
 * 2. 其他插件处理过程在这里被跳过（因为我们在预处理阶段）
 * 3. 将占位符恢复为代码块
 * 占位符数组存储在插件的 state 中
 */
function codePreprocess(content, context) {
  const state = context.state;
  const config = context.config;

  // 第一步：代码转占位符 - 保护代码内容（排除指定语言）
  const result = preprocessCodeBlocks(content, config.excludedLanguages);

  // 存储占位符数组到插件状态中
  state.codePlaceholders = result.codeBlockPlaceholders;
  state.inlineCodePlaceholders = result.inlineCodePlaceholders;

  // 注意：这里我们直接返回受保护的内容
  // 在预处理阶段，代码会被转换为占位符保护起来
  // 其他插件将处理受保护的内容，不会影响代码块
  // 然后在后处理阶段，我们可以通过 postprocess 钩子恢复代码
  return result.protectedText;
}

export { codePreprocess };
