import { emitRuntimeError } from '@djangocfg/ui-core/utils';

import { logger } from './logger';

/**
 * Safely escape string for use in CSS attribute selector
 */
function escapeCSS(str: string): string {
  return str.replace(/["\\]/g, '\\$&');
}

/**
 * Find target elements for a tour step.
 * Supports CSS selectors and data-tour-step-id attribute.
 */
export function findTargetElements(
  target: string | undefined,
  stepId: string
): HTMLElement[] {
  if (!target) {
    // Fallback to data-tour-step-id attribute
    try {
      const escapedStepId = escapeCSS(stepId);
      const elements = document.querySelectorAll<HTMLElement>(
        `[data-tour-step-id="${escapedStepId}"], [data-tour-step-id*="${escapedStepId}"]`
      );
      return filterValidElements(Array.from(elements));
    } catch (error) {
      const err = error instanceof Error ? error : new Error(String(error));
      logger.error(`Tour: Invalid stepId selector "${stepId}"`, { error: err.message, stepId });
      emitRuntimeError('Tour', `Invalid stepId: ${stepId}`, err);
      return [];
    }
  }

  // Try as CSS selector first
  try {
    const elements = document.querySelectorAll<HTMLElement>(target);
    const valid = filterValidElements(Array.from(elements));
    if (valid.length > 0) return valid;
  } catch (error) {
    const err = error instanceof Error ? error : new Error(String(error));
    logger.warn(`Tour: Invalid target selector "${target}"`, { error: err.message, target, stepId });
    emitRuntimeError('Tour', `Invalid selector: ${target}`, err);
    return [];
  }

  // Fallback to data attribute
  try {
    const escapedTarget = escapeCSS(target);
    const elements = document.querySelectorAll<HTMLElement>(
      `[data-tour-step-id="${escapedTarget}"], [data-tour-step-id*="${escapedTarget}"]`
    );
    return filterValidElements(Array.from(elements));
  } catch (error) {
    const err = error instanceof Error ? error : new Error(String(error));
    logger.error(`Tour: Invalid fallback selector for "${target}"`, { error: err.message, target, stepId });
    emitRuntimeError('Tour', `Invalid fallback selector: ${target}`, err);
    return [];
  }
}

/**
 * Filter out elements that are not visible or have zero dimensions.
 */
function filterValidElements(elements: HTMLElement[]): HTMLElement[] {
  return elements.filter((el) => {
    const rect = el.getBoundingClientRect();
    // Skip elements with zero dimensions
    if (rect.width === 0 && rect.height === 0) return false;
    // Skip hidden elements
    const style = window.getComputedStyle(el);
    if (style.display === 'none' || style.visibility === 'hidden') return false;
    return true;
  });
}

/**
 * Get computed border radius from element.
 */
export function getElementBorderRadius(element: HTMLElement): number {
  const style = window.getComputedStyle(element);
  const radius = parseFloat(style.borderRadius) || 0;
  return Math.min(radius, 20); // Cap at 20px for reasonable spotlight
}

/**
 * Check if element is in viewport.
 */
export function isElementInViewport(element: HTMLElement): boolean {
  const rect = element.getBoundingClientRect();
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= window.innerHeight &&
    rect.right <= window.innerWidth
  );
}
