import type { ComponentInternalInstance, Plugin, App } from 'vue';

/**
 * 全局文本混淆插件
 * 自动查找并替换所有文本节点
 */
// 修改Vue混淆插件以确保处理整个组件树
export const TextObfuscatorPlugin: Plugin = {
  install(app: App) {
    // 安装全局样式和解码脚本
    addObfuscationStyle();

    // 注册全局指令，直接处理元素内容
    app.directive('odata', {
      mounted(el) {
        processTextNodes(el, null);
        if (window.decodeObfuscatedContent) {
          setTimeout(() => window.decodeObfuscatedContent(el), 0);
        }
        setupMutationObserver(el);
      },
      updated(el) {
        processTextNodes(el, null);
        if (window.decodeObfuscatedContent) {
          setTimeout(() => window.decodeObfuscatedContent(el), 0);
        }
      }
    });

    // 在 app.mixin 中修改处理 $el 的部分
    app.mixin({
      mounted() {
        // 安全地获取组件的根元素(s)
        const rootElements = this.$el ?
          (this.$el.nodeType === Node.ELEMENT_NODE ?
            [this.$el] :
            (Array.isArray(this.$el) ? this.$el : [])) :
          [];

        // 处理每个根元素
        rootElements.forEach((rootElement: Element) => {
          if (!rootElement || !(rootElement instanceof Element)) return;

          // 1. 首先处理当前组件的根元素
          processTextNodes(rootElement, this);

          // 2. 递归处理所有子元素，确保覆盖所有文本节点
          const processAllChildNodes = (element: Element) => {
            if (!(element instanceof Element)) return;

            try {
              // 为每个子元素单独处理文本节点
              const childElements = element.querySelectorAll('*');
              childElements.forEach(childEl => {
                processTextNodes(childEl, null);
              });

              // 立即解码当前处理的元素
              if (window.decodeObfuscatedContent) {
                setTimeout(() => window.decodeObfuscatedContent(element), 0);
              }
            } catch (error) {
              console.error('Error processing child nodes:', error, element);
            }
          };

          // 处理整个组件树
          processAllChildNodes(rootElement);

          // 设置监听
          setupMutationObserver(rootElement);
        });
        // 添加：深度扫描所有包含纯文本的元素
        setTimeout(() => {
          const scanPureTextElements = (rootElement: Element) => {
            // 跳过已处理过的元素
            if (rootElement.hasAttribute && rootElement.hasAttribute('data-obfuscated')) {
              return;
            }

            // 检查是否为包含纯文本的元素（只有文本节点，没有元素节点）
            let hasOnlyTextNodes = false;
            let hasElementNodes = false;

            if (rootElement.childNodes && rootElement.childNodes.length > 0) {
              hasOnlyTextNodes = Array.from(rootElement.childNodes).some(
                node => node.nodeType === Node.TEXT_NODE && node.textContent && node.textContent.trim()
              );

              hasElementNodes = Array.from(rootElement.childNodes).some(
                node => node.nodeType === Node.ELEMENT_NODE
              );
            }

            // 如果元素只包含文本节点，并且不包含其他元素节点，则混淆它
            if (hasOnlyTextNodes && !hasElementNodes &&
              !SKIP_TAGS.includes(rootElement.tagName) &&
              !Array.from(rootElement.classList || []).some(cls => SKIP_CLASSES.includes(cls))) {
              processTextNodes(rootElement, null);
              if (window.decodeObfuscatedContent) {
                window.decodeObfuscatedContent(rootElement);
              }
            }

            // 递归处理子元素
            if (rootElement.children) {
              Array.from(rootElement.children).forEach(child => {
                scanPureTextElements(child);
              });
            }
          };

          // 从body开始扫描
          scanPureTextElements(document.body);
        }, 10); // 给DOM足够的时间渲染
      },

      updated() {
        // 安全地获取组件的根元素(s)
        const rootElements = this.$el ?
          (this.$el.nodeType === Node.ELEMENT_NODE ?
            [this.$el] :
            (Array.isArray(this.$el) ? this.$el : [])) :
          [];

        // 处理每个根元素
        rootElements.forEach((rootElement: Element | undefined) => {
          if (!rootElement || !(rootElement instanceof Element)) return;

          processTextNodes(rootElement, this);

          try {
            // 递归处理所有子元素
            const childElements = rootElement.querySelectorAll('*');
            childElements.forEach((childEl: Element) => {
              processTextNodes(childEl, null);
            });

            if (window.decodeObfuscatedContent) {
              setTimeout(() => window.decodeObfuscatedContent(rootElement), 0);
            }
          } catch (error) {
            console.error('Error processing updated component:', error, rootElement);
          }
        });
      }
    });
  }
};

// 声明全局函数类型
declare global {
  interface Window {
    decodeObfuscatedContent: (rootElement?: Element) => void;
  }
}

// 需要跳过的标签
const SKIP_TAGS = ['SCRIPT', 'STYLE', 'TEXTAREA', 'INPUT', 'PRE', 'CODE'];
// 需要跳过的类名
const SKIP_CLASSES = ['no-obfuscate', 'op-no-obfuscate'];

/**
 * 处理元素中的所有文本节点
 */
function processTextNodes(element: Element, instance: ComponentInternalInstance | null) {
  if (!element || element.nodeType !== Node.ELEMENT_NODE) {
    return;
  }
  // 为 DIV 元素增加优先处理逻辑
  if (element.tagName === 'DIV' && !element.hasAttribute('data-obfuscated')) {
    // 对于DIV元素，特殊处理其直接子文本节点
    let hasTextContent = false;
    for (let i = 0; i < element.childNodes.length; i++) {
      const node = element.childNodes[i];
      if (node.nodeType === Node.TEXT_NODE && node.textContent && node.textContent.trim() !== '') {
        hasTextContent = true;
        break;
      }
    }

    // 如果DIV中有直接的文本内容，标记它需要被处理
    if (hasTextContent) {
      // 只处理未混淆过的DIV
      const textContent = Array.from(element.childNodes)
        .filter(node => node.nodeType === Node.TEXT_NODE && node.textContent)
        .map(node => node.textContent).join('').trim();

      if (textContent) {
        // 替换整个DIV的内容
        const originalHTML = element.innerHTML;
        const processedHTML = obfuscateText(textContent);
        element.innerHTML = processedHTML + originalHTML.replace(textContent, '');
        element.setAttribute('data-obfuscated', 'true');
      }
    }
  }
  // 跳过带有特定标记的元素（避免重复处理）
  if (element.hasAttribute('data-obfuscated') ||
    !element ||
    SKIP_TAGS.includes(element.tagName) ||
    Array.from(element.classList).some(cls => SKIP_CLASSES.includes(cls))) {
    return;
  }

  // 使用 TreeWalker 遍历所有文本节点
  const walker = document.createTreeWalker(
    element,
    NodeFilter.SHOW_TEXT,
    {
      acceptNode(node) {
        // 不处理完全空的文本节点
        if (!node.textContent) {
          return NodeFilter.FILTER_REJECT;
        }

        // 检查父节点是否应该被跳过
        const parent = node.parentElement;
        if (parent && (
          SKIP_TAGS.includes(parent.tagName) ||
          parent.hasAttribute('data-obfuscated') ||
          Array.from(parent.classList || []).some(cls => SKIP_CLASSES.includes(cls))
        )) {
          return NodeFilter.FILTER_REJECT;
        }

        // 如果只包含空白且不是段落的首个节点，则跳过
        if (node.textContent.trim() === '' &&
          !(parent?.tagName === 'P' && node === parent.firstChild)) {
          return NodeFilter.FILTER_REJECT;
        }

        return NodeFilter.FILTER_ACCEPT;
      }
    }
  );

  // 收集需要处理的文本节点
  const textNodes: Text[] = [];
  let currentNode: Node | null = walker.nextNode();

  while (currentNode) {
    textNodes.push(currentNode as Text);
    currentNode = walker.nextNode();
  }

  // 预先计算所有混淆内容，减少DOM操作次数
  const fragments: DocumentFragment[] = [];
  const nodesToReplace: Text[] = [];

  // 在处理文本节点前，移除所有前导空格
  for (const textNode of textNodes) {
    const text = textNode.textContent;
    if (!text) continue;

    // 重要修改：检测是否是段落的首个文本节点，无条件移除开头的空白
    let processedText = text;
    if (textNode.parentElement?.tagName === 'P' &&
      textNode === textNode.parentElement.firstChild) {
      // 去除开头的空白，无论什么情况
      processedText = text.replace(/^\s+/, '');
      // 如果去除空白后为空，直接跳过这个节点
      if (!processedText) continue;
    }

    try {
      // 创建文档碎片来存储混淆后的内容
      const fragment = document.createDocumentFragment();
      const tempContainer = document.createElement('div');
      tempContainer.innerHTML = obfuscateText(processedText);

      // 将内容移动到碎片中
      while (tempContainer.firstChild) {
        fragment.appendChild(tempContainer.firstChild);
      }

      fragments.push(fragment);
      nodesToReplace.push(textNode);
    } catch (error) {
      console.error('Error processing text node:', error);
    }
  }

  // 批量替换节点，减少回流
  for (let i = 0; i < nodesToReplace.length; i++) {
    const textNode = nodesToReplace[i];
    const fragment = fragments[i];

    if (textNode.parentNode) {
      textNode.parentNode.replaceChild(fragment, textNode);
    }
  }
}

/**
 * 设置 MutationObserver 来监听 DOM 变化
 */
function setupMutationObserver(element: Element) {
  if (!element) return;

  const observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
      if (mutation.type === 'childList' && mutation.addedNodes.length) {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === Node.ELEMENT_NODE) {
            processTextNodes(node as Element, null);
            // 观察到新元素后立即解码
            if (window.decodeObfuscatedContent) {
              window.decodeObfuscatedContent(node as Element);
            }
          }
        });
      }
    }
  });

  observer.observe(element, {
    childList: true,
    subtree: true
  });
}

/**
 * 生成随机噪声标签和注释
 */
function getRandomNoise() {
  const noiseTypes = [
    // HTML注释
    () => `<!--${Math.random().toString(36).substring(2, 6)}-->`,
    // 空的自定义元素
    () => {
      const tags = ['z-nil', 'z-void', 'z-null', 'z-fake', 'z-empty'];
      const tag = tags[Math.floor(Math.random() * tags.length)];
      return `<${tag}></${tag}>`;
    },
    // 带随机属性的自定义元素
    () => {
      const attr = `data-${Math.random().toString(36).substring(2, 7)}`;
      const value = Math.random().toString(36).substring(2, 10);
      return `<z-attr ${attr}="${value}"></z-attr>`;
    },
    // 带随机文本的隐藏元素
    () => {
      const text = Math.random().toString(36).substring(2, 8);
      return `<z-text>${text}</z-text>`;
    }
  ];

  // 随机选择一种噪声类型
  const noiseGenerator = noiseTypes[Math.floor(Math.random() * noiseTypes.length)];
  return noiseGenerator();
}

/**
 * 混淆文本 - 将文本拆分成单词并分别存储，使用自定义z-标签
 */
function obfuscateText(text: string): string {
  if (!text) return '';

  // 首先移除文本开头的所有空白字符以解决段落首行缩进问题
  text = text.replace(/^\s+/, '');
  if (!text) return '';

  // 使用正则表达式将文本拆分为单词和空格，保持完整性
  const words = text.split(/(\s+)/);
  let result = '<z-wrap data-obfuscated="true">';

  // 过滤掉空字符串，避免生成空的z-span元素
  const filteredWords = words.filter(word => word.length > 0);

  // 为每个单词创建一个独立的自定义元素
  filteredWords.forEach((word, index) => {
    // 对空格和特殊字符进行特殊处理
    if (/^\s+$/.test(word)) {
      // 改进：更精确地处理各种换行符
      if (/[\n\r]/.test(word)) {
        // 将所有类型的换行符分割出来，但仅在实际有换行符时才添加z-break元素
        result += '<z-break></z-break>';
      } else {
        // 纯空格的情况 - 对连续空格合并处理，避免添加过多z-space
        result += '<z-space></z-space>';
      }
      return;
    }

    // 随机在单词前添加噪声，但减少频率
    if (Math.random() > 0.85) {
      result += getRandomNoise();
    }

    // 为了提高效率，固定属性名
    const attrId = `data`;

    // 将单词编码为Base64
    const encodedWord = btoa(encodeURIComponent(word));

    // 随机选择z-span或z-strong标签增加混淆度
    const tagName = Math.random() > 0.5 ? 'z-span' : 'z-strong';

    // 添加标签开始部分
    result += `<${tagName} data-${attrId}="${encodedWord}" data-preload="true">`;

    // 随机在标签内添加隐藏内容，但减少频率
    if (Math.random() > 0.8) {
      const fakeText = Math.random().toString(36).substring(2, 5 + Math.floor(Math.random() * 5));
      result += `<z-hidden>${fakeText}</z-hidden>`;
    }

    // 闭合标签
    result += `</${tagName}>`;

    // 随机在单词后添加噪声，但减少频率
    if (Math.random() > 0.85) {
      result += getRandomNoise();
    }
  });

  result += '</z-wrap>';
  return result;
}

/**
 * 添加显示混淆内容的样式和解码脚本
 */
function addObfuscationStyle() {
  // 添加样式
  if (!document.getElementById('obfuscation-style')) {
    const style = document.createElement('style');
    style.id = 'obfuscation-style';
    style.textContent = `
      /* 自定义元素基本样式 */
      z-wrap {
        display: inline;
        white-space: normal;
        user-select: none; /* 阻止文本选择 */
        text-indent: 0 !important; /* 确保无缩进 */
      }
      
      /* 添加一个类来允许选择文本的情况 */
      .allow-select z-wrap {
        user-select: text;
      }
      
      /* 确保段落中的混淆内容没有开头缩进 */
      p > z-wrap:first-child {
        text-indent: 0 !important;
        margin-left: 0 !important;
        padding-left: 0 !important;
      }
      
      /* 处理所有p标签，确保没有多余空间 */
      p {
        text-indent: 0;
      }
      
      z-span, z-strong {
        display: inline-block;
        position: relative;
        opacity: 1;
        transition: opacity 0.1s ease;
        margin: 0;
        padding: 0;
      }
      
      /* 控制右侧间距 */
      z-span + z-span, z-strong + z-strong, z-span + z-strong, z-strong + z-span {
        margin-left: 0.1em;
      }
      
      /* 移除最后一个元素的右侧间距 */
      z-span:last-child, z-strong:last-child {
        margin-right: 0;
      }
      
      z-span::after, z-strong::after {
        content: attr(data-content);
        position: relative;
        pointer-events: none;
      }
      
      /* 空格元素 - 精确控制宽度 */
      z-space {
        display: inline-block;
        width: 0.25em;
        margin: 0;
        padding: 0;
      }
      
      /* 空的z-span/z-strong元素不应该显示 */
      z-span:not([data-content]), z-strong:not([data-content]) {
        display: none;
      }
      
      /* 换行元素 - 强制换行且完全没有尺寸 */
      z-break {
        display: block !important;
        height: 0 !important;
        width: 0 !important;
        margin: 0 !important;
        padding: 0 !important;
        border: none !important;
        line-height: 0 !important;
        font-size: 0 !important;
        overflow: hidden !important;
      }
      
      /* 隐藏所有噪声元素 */
      z-nil, z-void, z-null, z-fake, z-empty, z-attr, z-text, z-hidden {
        display: none;
        width: 0;
        height: 0;
        opacity: 0;
        overflow: hidden;
        position: absolute;
        visibility: hidden;
      }
      
      /* 预加载状态 */
      [data-preload="true"] {
        min-width: 0.5em;
        min-height: 1em;
      }
    `;
    document.head.appendChild(style);
  }

  // 添加自定义元素注册，确保所有浏览器都能正确处理
  const scriptCustomElements = document.createElement('script');
  scriptCustomElements.textContent = `
    // 注册所有自定义元素
    if ('customElements' in window) {
      customElements.define('z-wrap', class extends HTMLElement {});
      customElements.define('z-span', class extends HTMLElement {});
      customElements.define('z-strong', class extends HTMLElement {});
      customElements.define('z-space', class extends HTMLElement {});
      customElements.define('z-break', class extends HTMLElement {});
      
      // 注册噪声元素
      customElements.define('z-nil', class extends HTMLElement {});
      customElements.define('z-void', class extends HTMLElement {});
      customElements.define('z-null', class extends HTMLElement {});
      customElements.define('z-fake', class extends HTMLElement {});
      customElements.define('z-empty', class extends HTMLElement {});
      customElements.define('z-attr', class extends HTMLElement {});
      customElements.define('z-text', class extends HTMLElement {});
      customElements.define('z-hidden', class extends HTMLElement {});
    }
  `;
  document.head.appendChild(scriptCustomElements);

  // 添加提前解码的脚本，放在<head>顶部优先加载
  if (!document.getElementById('obfuscation-script')) {
    const script = document.createElement('script');
    script.id = 'obfuscation-script';
    script.textContent = `
      (function() {
        // 定义解码函数并暴露为全局函数
        window.decodeObfuscatedContent = function(rootElement) {
          const root = rootElement || document.body;
          const elements = root.querySelectorAll('z-span[data-preload="true"], z-strong[data-preload="true"]');
          
          if (elements.length === 0) return;
          
          // 使用requestIdleCallback或setTimeout在空闲时运行，避免阻塞渲染
          const runWhenIdle = window.requestIdleCallback || 
            function(cb) { setTimeout(cb, 1); };
          
          runWhenIdle(() => {
            elements.forEach(el => {
              // 避免重复解码
              if (el.hasAttribute('data-content')) return;
              
              // 找到编码数据
              const dataAttr = el.getAttribute('data-data');
              if (dataAttr) {
                try {
                  // 解码并设置
                  const decodedWord = decodeURIComponent(atob(dataAttr));
                  el.setAttribute('data-content', decodedWord);
                  el.removeAttribute('data-preload');
                } catch (e) {
                  // 解码失败时跳过
                }
              }
            });
          });
        };
        
        // 页面加载完成后立即执行一次全局解码
        if (document.readyState === 'loading') {
          document.addEventListener('DOMContentLoaded', function() {
            window.decodeObfuscatedContent();
          });
        } else {
          window.decodeObfuscatedContent();
        }
        
        // 使用IntersectionObserver优化解码性能
        if ('IntersectionObserver' in window) {
          const decodeObserver = new IntersectionObserver(
            (entries, observer) => {
              entries.forEach(entry => {
                if (entry.isIntersecting) {
                  // 容器进入视口时解码其内容
                  window.decodeObfuscatedContent(entry.target);
                  observer.unobserve(entry.target);
                }
              });
            },
            { rootMargin: '200px 0px' } // 提前200像素开始解码
          );
          
          // 监听所有混淆容器
          function observeContainers() {
            document.querySelectorAll('z-wrap').forEach(container => {
              decodeObserver.observe(container);
            });
          }
          
          // 初始观察
          if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', observeContainers);
          } else {
            observeContainers();
          }
          
          // 定期检查新容器
          setInterval(observeContainers, 2000);
        } else {
          // 降级方案：定期全局检查
          setInterval(() => window.decodeObfuscatedContent(), 1000);
        }
      })();
    `;

    // 将脚本添加到head的最前面，确保尽早加载
    if (document.head.firstChild) {
      document.head.insertBefore(script, document.head.firstChild);
    } else {
      document.head.appendChild(script);
    }
  }
}