/* eslint-disable */
// wait-for-element-helper.js
// This script is injected into the page to handle waiting for elements to appear

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

  /**
   * Wait for an element to appear on the page
   * @param {string} selector - CSS selector for the element to wait for
   * @param {number} timeout - Timeout in milliseconds (default: 10000)
   * @param {boolean} visible - Whether the element should be visible (default: true)
   * @returns {Promise<Object>} - Result of the wait operation
   */
  async function waitForElement(selector, timeout = 10000, visible = true) {
    const startTime = Date.now();

    return new Promise((resolve) => {
      let observer = null;
      let timeoutId = null;
      let visibilityCheckInterval = null;

      const cleanup = () => {
        if (observer) {
          observer.disconnect();
          observer = null;
        }
        if (timeoutId) {
          clearTimeout(timeoutId);
          timeoutId = null;
        }
        if (visibilityCheckInterval) {
          clearInterval(visibilityCheckInterval);
          visibilityCheckInterval = null;
        }
      };

      const checkElementAndResolve = (foundElement) => {
        const foundAt = Date.now() - startTime;
        cleanup();
        resolve({
          success: true,
          message: `Element with selector "${selector}" found${visible ? ' and visible' : ''} after ${foundAt}ms`,
          timedOut: false,
          foundAt,
          elementInfo: getElementInfo(foundElement),
        });
      };

      const resolveTimeout = (message) => {
        cleanup();
        resolve({
          success: false,
          message,
          timedOut: true,
          foundAt: null,
          elementInfo: null,
        });
      };

      const resolveError = (error) => {
        cleanup();
        resolve({
          success: false,
          message: `Error while waiting for element: ${error.message}`,
          timedOut: false,
          foundAt: null,
          elementInfo: null,
        });
      };

      try {
        // 首先立即检查一次元素是否已存在
        const initialCheck = () => {
          const elements = document.querySelectorAll(selector);

          if (elements.length > 0) {
            if (!visible) {
              // 不需要检查可见性，直接返回第一个元素
              checkElementAndResolve(elements[0]);
              return true;
            }

            // 需要检查可见性
            for (const element of elements) {
              if (isElementVisible(element)) {
                checkElementAndResolve(element);
                return true;
              }
            }

            // 元素存在但不可见，需要继续监听可见性变化
            return false;
          }

          // 元素不存在，需要监听 DOM 变化
          return false;
        };

        // 执行初始检查
        if (initialCheck()) {
          return; // 元素已找到，直接返回
        }

        // 设置超时
        timeoutId = setTimeout(() => {
          const elements = document.querySelectorAll(selector);
          if (elements.length > 0) {
            resolveTimeout(
              `Element with selector "${selector}" found but not visible within ${timeout}ms`,
            );
          } else {
            resolveTimeout(`Element with selector "${selector}" not found within ${timeout}ms`);
          }
        }, timeout);

        // 如果元素存在但不可见，定期检查可见性
        const existingElements = document.querySelectorAll(selector);
        if (existingElements.length > 0 && visible) {
          visibilityCheckInterval = setInterval(() => {
            for (const element of existingElements) {
              if (isElementVisible(element)) {
                checkElementAndResolve(element);
                return;
              }
            }
          }, 100); // 每100ms检查一次可见性
        }

        // 使用 MutationObserver 监听 DOM 变化
        observer = new MutationObserver((mutations) => {
          try {
            let shouldCheck = false;

            // 检查是否有相关的 DOM 变化
            for (const mutation of mutations) {
              if (mutation.type === 'childList') {
                // 有节点添加或删除
                if (mutation.addedNodes.length > 0) {
                  shouldCheck = true;
                  break;
                }
              } else if (mutation.type === 'attributes') {
                // 属性变化可能影响可见性
                const target = mutation.target;
                if (target.nodeType === Node.ELEMENT_NODE) {
                  const attrName = mutation.attributeName;
                  if (attrName === 'class' || attrName === 'style' || attrName === 'hidden') {
                    shouldCheck = true;
                    break;
                  }
                }
              }
            }

            if (shouldCheck) {
              const elements = document.querySelectorAll(selector);

              if (elements.length > 0) {
                if (!visible) {
                  // 不需要检查可见性
                  checkElementAndResolve(elements[0]);
                  return;
                }

                // 检查可见性
                for (const element of elements) {
                  if (isElementVisible(element)) {
                    checkElementAndResolve(element);
                    return;
                  }
                }
              }
            }
          } catch (error) {
            resolveError(error);
          }
        });

        // 开始观察 DOM 变化
        observer.observe(document.body, {
          childList: true,
          subtree: true,
          attributes: true,
          attributeFilter: ['class', 'style', 'hidden'],
        });
      } catch (error) {
        resolveError(error);
      }
    });
  }

  /**
   * Check if an element is visible
   * @param {Element} element - The element to check
   * @returns {boolean} - True if the element is visible
   */
  function isElementVisible(element) {
    if (!element) return false;

    // Check if element is hidden via CSS
    const style = window.getComputedStyle(element);
    if (
      style.display === 'none' ||
      style.visibility === 'hidden' ||
      style.opacity === '0' ||
      element.hidden
    ) {
      return false;
    }

    // Check if element has dimensions
    const rect = element.getBoundingClientRect();
    if (rect.width === 0 || rect.height === 0) {
      return false;
    }

    // Check if element is within viewport (at least partially)
    if (
      rect.bottom < 0 ||
      rect.top > window.innerHeight ||
      rect.right < 0 ||
      rect.left > window.innerWidth
    ) {
      return false;
    }

    return true;
  }

  /**
   * Get information about an element
   * @param {Element} element - The element to get info about
   * @returns {Object} - Element information
   */
  function getElementInfo(element) {
    if (!element) return null;

    const rect = element.getBoundingClientRect();
    const style = window.getComputedStyle(element);

    return {
      tagName: element.tagName,
      id: element.id || null,
      className: element.className || null,
      text: element.textContent?.trim().substring(0, 200) || '',
      href: element.href || null,
      type: element.type || null,
      value: element.value || null,
      isVisible: isElementVisible(element),
      rect: {
        x: rect.x,
        y: rect.y,
        width: rect.width,
        height: rect.height,
        top: rect.top,
        left: rect.left,
        bottom: rect.bottom,
        right: rect.right,
      },
      style: {
        display: style.display,
        visibility: style.visibility,
        opacity: style.opacity,
      },
      attributes: Array.from(element.attributes).reduce((acc, attr) => {
        acc[attr.name] = attr.value;
        return acc;
      }, {}),
    };
  }

  // Listen for messages from the extension
  chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
    if (request.action === 'waitForElement') {
      waitForElement(request.selector, request.timeout, request.visible)
        .then(sendResponse)
        .catch((error) => {
          sendResponse({
            success: false,
            message: `Unexpected error: ${error.message}`,
            timedOut: false,
            foundAt: null,
            elementInfo: null,
          });
        });
      return true; // Indicates async response
    } else if (request.action === 'chrome_wait_for_element_ping') {
      sendResponse({ status: 'pong' });
      return false;
    }
  });
}
