/* eslint-disable */
// dom-utils.js
// 通用 DOM 操作工具函数

if (window.__DOM_UTILS_INITIALIZED__) {
  // Already initialized, skip
} else {
  window.__DOM_UTILS_INITIALIZED__ = true;

  /**
   * 睡眠函数
   * @param {number} time - 睡眠时间（毫秒）
   * @returns {Promise} 睡眠 Promise
   */
  function sleep(time) {
    return new Promise((resolve) => {
      setTimeout(() => resolve(), time);
    });
  }

  /**
   * 使用 XPath 等待元素出现
   * @param {string} xpath - XPath 表达式
   * @param {number} timeout - 超时时间（毫秒），默认 10 秒
   * @returns {Promise<Element>} 找到的元素
   */
  async function waitForElementXPath(xpath, timeout = 10000) {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const interval = setInterval(() => {
        const result = document.evaluate(
          xpath,
          document,
          null,
          XPathResult.FIRST_ORDERED_NODE_TYPE,
          null,
        );
        const element = result.singleNodeValue;
        if (element) {
          clearInterval(interval);
          resolve(element);
        } else if (Date.now() - startTime > timeout) {
          clearInterval(interval);
          reject(new Error(`Element ${xpath} not found within ${timeout}ms`));
        }
      }, 100);
    });
  }

  /**
   * 使用选择器等待元素出现
   * @param {string} selector - CSS 选择器
   * @param {number} timeout - 超时时间（毫秒），默认 10 秒
   * @returns {Promise<Element>} 找到的元素
   */
  async function waitForElement(selector, timeout = 10000) {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const interval = setInterval(() => {
        const element = document.querySelector(selector);
        if (element) {
          clearInterval(interval);
          resolve(element);
        } else if (Date.now() - startTime > timeout) {
          clearInterval(interval);
          reject(new Error(`Element ${selector} not found within ${timeout}ms`));
        }
      }, 100);
    });
  }

  /**
   * 等待元素消失
   * @param {string} selector - CSS 选择器
   * @param {number} timeout - 超时时间（毫秒），默认 10 秒
   * @returns {Promise<void>}
   */
  async function waitForElementToDisappear(selector, timeout = 10000) {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const interval = setInterval(() => {
        const element = document.querySelector(selector);
        if (!element) {
          clearInterval(interval);
          resolve();
        } else if (Date.now() - startTime > timeout) {
          clearInterval(interval);
          reject(new Error(`Element ${selector} did not disappear within ${timeout}ms`));
        }
      }, 100);
    });
  }

  /**
   * 等待指定类名的元素出现
   * @param {string} className - 类名
   * @param {number} timeout - 超时时间（毫秒），默认 10 秒
   * @returns {Promise<void>}
   */
  function waitForElementsByClass(className, timeout = 10000) {
    return new Promise((resolve) => {
      const startTime = Date.now();
      const checkInterval = setInterval(() => {
        if (
          document.querySelectorAll(`.${className}`).length > 0 ||
          Date.now() - startTime > timeout
        ) {
          clearInterval(checkInterval);
          resolve();
        }
      }, 100);
    });
  }

  /**
   * 模拟人工输入（支持可编辑元素和普通输入框）
   * @param {Element} element - 目标元素
   * @param {string} text - 要输入的文本
   * @param {boolean} simulate - 是否模拟逐字符输入，默认 false
   * @returns {Promise<void>}
   */
  async function simulateTyping(element, text, simulate = false) {
    if (simulate) {
      // 模拟逐个字符输入
      for (let char of text) {
        if (element.isContentEditable) {
          element.innerText += char;
        } else {
          element.value += char;
        }
        element.dispatchEvent(new Event('input', { bubbles: true }));
        await new Promise((resolve) => setTimeout(resolve, 50 + Math.random() * 50));
      }
    } else {
      // 直接输入，追加内容
      if (element.isContentEditable) {
        element.innerText += text;
      } else {
        element.value += text;
      }
      element.dispatchEvent(new Event('input', { bubbles: true }));
      await sleep(2000);
    }
  }

  /**
   * 高级模拟输入（支持更多事件）
   * @param {Element} element - 目标元素
   * @param {string} char - 要输入的字符
   * @returns {Promise<void>}
   */
  async function simulateInput(element, char) {
    element.focus();

    // 使用 execCommand 插入文本
    document.execCommand('insertText', false, char);

    // 创建并分发输入事件
    const inputEvent = new InputEvent('input', {
      inputType: 'insertText',
      data: char,
      bubbles: true,
      cancelable: true,
    });
    element.dispatchEvent(inputEvent);

    // 创建并分发 keydown 事件
    const keydownEvent = new KeyboardEvent('keydown', {
      key: char,
      keyCode: char.charCodeAt(0),
      which: char.charCodeAt(0),
      bubbles: true,
      cancelable: true,
    });
    element.dispatchEvent(keydownEvent);

    // 创建并分发 keyup 事件
    const keyupEvent = new KeyboardEvent('keyup', {
      key: char,
      keyCode: char.charCodeAt(0),
      which: char.charCodeAt(0),
      bubbles: true,
      cancelable: true,
    });
    element.dispatchEvent(keyupEvent);

    // 等待一小段时间，模拟真实输入速度
    await new Promise((resolve) => setTimeout(resolve, 20));
  }

  /**
   * 检查元素是否在视窗中可见
   * @param {Element} element - 要检查的元素
   * @returns {boolean} 是否可见
   */
  function isElementInViewport(element) {
    const rect = element.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  }

  /**
   * 滚动到元素位置
   * @param {Element} element - 目标元素
   * @param {string} behavior - 滚动行为，默认 'smooth'
   */
  function scrollToElement(element, behavior = 'smooth') {
    element.scrollIntoView({ behavior, block: 'center' });
  }

  /**
   * 模拟鼠标事件
   * @param {Element} element - 目标元素
   * @param {string} eventType - 事件类型（mousedown, mouseup, click 等）
   * @returns {Promise<void>}
   */
  async function simulateMouseEvent(element, eventType = 'click') {
    // 确保元素可见
    element.scrollIntoView();
    await sleep(100);

    const event = new MouseEvent(eventType, {
      bubbles: true,
      cancelable: true,
    });
    element.dispatchEvent(event);
  }

  /**
   * 等待并点击元素
   * @param {string} selector - CSS 选择器或 XPath
   * @param {boolean} isXPath - 是否为 XPath
   * @param {number} timeout - 超时时间
   * @returns {Promise<Element>}
   */
  async function waitAndClick(selector, isXPath = false, timeout = 10000) {
    const element = isXPath
      ? await waitForElementXPath(selector, timeout)
      : await waitForElement(selector, timeout);

    await simulateMouseEvent(element);
    return element;
  }

  /**
   * 批量等待元素（任一出现即返回）
   * @param {Array<{selector: string, isXPath?: boolean}>} selectors - 选择器数组
   * @param {number} timeout - 超时时间
   * @returns {Promise<{element: Element, index: number}>}
   */
  async function waitForAnyElement(selectors, timeout = 10000) {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const interval = setInterval(() => {
        for (let i = 0; i < selectors.length; i++) {
          const { selector, isXPath = false } = selectors[i];
          let element;

          if (isXPath) {
            const result = document.evaluate(
              selector,
              document,
              null,
              XPathResult.FIRST_ORDERED_NODE_TYPE,
              null,
            );
            element = result.singleNodeValue;
          } else {
            element = document.querySelector(selector);
          }

          if (element) {
            clearInterval(interval);
            resolve({ element, index: i });
            return;
          }
        }

        if (Date.now() - startTime > timeout) {
          clearInterval(interval);
          reject(new Error(`No elements found within ${timeout}ms`));
        }
      }, 100);
    });
  }

  // 将函数暴露到全局窗口对象
  window.DOMUtils = {
    sleep,
    waitForElementXPath,
    waitForElement,
    waitForElementToDisappear,
    waitForElementsByClass,
    simulateTyping,
    simulateInput,
    isElementInViewport,
    scrollToElement,
    simulateMouseEvent,
    waitAndClick,
    waitForAnyElement,
  };
}
