/**
 * InfoPanelOverlay Component
 *
 * Overlay panel that displays header, title, info spans, text, and image cards.
 * Section-based structure similar to Gallery for consistent styling.
 * Positioned absolutely within the canvas (not fullscreen).
 * Supports keyboard navigation, click outside to close, and mobile touch.
 */

import React, {
  useState,
  useEffect,
  useCallback,
  useRef,
  useMemo,
} from 'react';
import type {
  CanvasElement,
  InfoPanelImage,
  InfoPanelImageClickAction,
  InfoPanelLinkClickAction,
  InfoPanelSectionInstance,
} from '../../types/constructor';
import { getInfoPanelSections } from '../../types/constructor';
import { resolveAssetPlaybackUrl } from '../../lib/assetUrl';
import {
  buildInfoPanelHeaderStyle,
  buildInfoPanelTitleStyle,
  buildInfoPanelTextStyle,
  buildInfoPanelSpanStyle,
  buildInfoPanelSpanGridStyleWithSection,
  buildInfoPanelCardStyle,
  buildInfoPanelCardTitleStyle,
  buildInfoPanelCardGridStyleWithSection,
} from '../../lib/infoPanelSectionStyles';

interface InfoPanelOverlayProps {
  element: CanvasElement;
  onClose: () => void;
  resolveUrl?: (url: string | undefined) => string;
  letterboxStyles?: React.CSSProperties;
  /** CSS custom properties including --cu for canvas units */
  cssVars?: React.CSSProperties;
  /** Callback when an image/360 is clicked. Pass null to close the detail panel. */
  onImageClick: (image: InfoPanelImage | null) => void;
  /** Callback when an image/video/360 group should open in fullscreen gallery mode */
  onOpenGallery?: (items: InfoPanelImage[], initialIndex: number) => void;
  /** Callback when an image thumbnail is selected */
  onSelectImage?: (imageId: string) => void;
  /** Callback when an Info Panel item targets an internal page slug */
  onNavigateToPage?: (targetPageSlug: string) => void;
  /** Callback when an Info Panel item targets an external URL */
  onOpenExternalUrl?: (url: string) => void;
  /** Callback when a media item should replace the current screen background */
  onUseAsBackground?: (image: InfoPanelImage) => void;
  /** Whether this overlay instance should render the fullscreen backdrop layer */
  renderBackdrop?: boolean;
  /** Optional close handler for backdrop clicks; defaults to onClose */
  onBackdropClose?: () => void;
  isEditMode?: boolean;
  /** Callback when panel position changes (edit mode only) */
  onPanelPositionChange?: (xPercent: number, yPercent: number) => void;
  /** Currently active 360° item ID (for toggle state sync with parent) */
  active360ItemId?: string | null;
}

const VideoThumbnail: React.FC<{
  src: string;
  caption?: string;
}> = ({ src, caption }) => {
  const [isReady, setIsReady] = useState(false);

  return (
    <div className='relative h-full w-full overflow-hidden bg-black'>
      <video
        src={src}
        className='h-full w-full object-cover'
        muted
        playsInline
        preload='metadata'
        aria-label={caption || 'Video thumbnail'}
        style={{
          pointerEvents: 'none',
          opacity: isReady ? 1 : 0,
          transition: 'opacity 160ms ease-out',
        }}
        onLoadedData={(event) => {
          setIsReady(true);
          const video = event.currentTarget;
          if (video.duration > 0.25 && video.currentTime < 0.1) {
            try {
              video.currentTime = 0.1;
            } catch {
              // Some browsers disallow seeking before metadata is fully ready.
            }
          }
        }}
        onError={() => setIsReady(false)}
      />
      {!isReady && (
        <div className='absolute inset-0 flex items-center justify-center text-white/40'>
          <svg
            xmlns='http://www.w3.org/2000/svg'
            fill='none'
            viewBox='0 0 24 24'
            strokeWidth={1.5}
            stroke='currentColor'
            className='h-7 w-7'
          >
            <path
              strokeLinecap='round'
              strokeLinejoin='round'
              d='m5.25 5.653 8.954 5.722a.75.75 0 0 1 0 1.25L5.25 18.347A.75.75 0 0 1 4.125 17.722V6.278a.75.75 0 0 1 1.125-.625Z'
            />
          </svg>
        </div>
      )}
      <div className='absolute inset-0 flex items-center justify-center bg-black/10'>
        <span className='flex h-8 w-8 items-center justify-center rounded-full bg-black/55 text-white shadow'>
          <svg
            xmlns='http://www.w3.org/2000/svg'
            fill='currentColor'
            viewBox='0 0 24 24'
            className='ml-0.5 h-4 w-4'
            aria-hidden='true'
          >
            <path d='M8 5v14l11-7z' />
          </svg>
        </span>
      </div>
    </div>
  );
};

const InfoPanelOverlay: React.FC<InfoPanelOverlayProps> = ({
  element,
  onClose,
  resolveUrl,
  letterboxStyles,
  cssVars,
  onImageClick,
  onOpenGallery,
  onSelectImage,
  onNavigateToPage,
  onOpenExternalUrl,
  onUseAsBackground,
  renderBackdrop = true,
  onBackdropClose,
  isEditMode = false,
  onPanelPositionChange,
  active360ItemId,
}) => {
  const resolve = resolveUrl ?? resolveAssetPlaybackUrl;
  const overlayRef = useRef<HTMLDivElement>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const [isVisible, setIsVisible] = useState(false);
  const [isDragging, setIsDragging] = useState(false);
  const dragStartRef = useRef<{
    x: number;
    y: number;
    panelX: number;
    panelY: number;
  } | null>(null);

  // Section styles computed from element settings
  const headerStyle = useMemo(
    () => buildInfoPanelHeaderStyle(element),
    [element],
  );
  const titleStyle = useMemo(
    () => buildInfoPanelTitleStyle(element),
    [element],
  );
  const textStyle = useMemo(() => buildInfoPanelTextStyle(element), [element]);
  const spanStyle = useMemo(() => buildInfoPanelSpanStyle(element), [element]);
  const cardStyle = useMemo(() => buildInfoPanelCardStyle(element), [element]);
  const cardTitleStyle = useMemo(
    () => buildInfoPanelCardTitleStyle(element),
    [element],
  );
  // Get section instances
  const sections = useMemo(() => getInfoPanelSections(element), [element]);

  const openExternalUrl = useCallback(
    (url: string) => {
      const trimmed = url.trim();
      if (!trimmed) return;
      if (onOpenExternalUrl) {
        onOpenExternalUrl(trimmed);
        return;
      }
      const href = /^https?:\/\//i.test(trimmed)
        ? trimmed
        : `https://${trimmed}`;
      window.open(href, '_blank', 'noopener,noreferrer');
    },
    [onOpenExternalUrl],
  );

  const handleLinkDestination = useCallback(
    (target: {
      clickAction?: InfoPanelLinkClickAction;
      targetPageSlug?: string;
      externalUrl?: string;
    }): boolean => {
      if (target.clickAction === 'target_page' && target.targetPageSlug) {
        onNavigateToPage?.(target.targetPageSlug);
        return true;
      }
      if (target.clickAction === 'external_url' && target.externalUrl) {
        openExternalUrl(target.externalUrl);
        return true;
      }
      return false;
    },
    [onNavigateToPage, openExternalUrl],
  );

  const handleImageDestination = useCallback(
    (
      image: InfoPanelImage,
      section: InfoPanelSectionInstance,
      items?: InfoPanelImage[],
    ) => {
      if (image.useAsBackground) {
        onUseAsBackground?.(image);
        return;
      }

      const clickAction: InfoPanelImageClickAction =
        image.clickAction || 'panel';

      if (clickAction === 'target_page' && image.targetPageSlug) {
        onNavigateToPage?.(image.targetPageSlug);
        return;
      }

      if (clickAction === 'external_url' && image.externalUrl) {
        openExternalUrl(image.externalUrl);
        return;
      }

      const sectionMode =
        section.mediaOpenMode ||
        (clickAction === 'fullscreen' ? 'fullscreen' : 'panel');

      if (sectionMode === 'fullscreen' && onOpenGallery && items?.length) {
        onOpenGallery(
          items,
          Math.max(
            0,
            items.findIndex((item) => item.id === image.id),
          ),
        );
        return;
      }

      onImageClick(image);
    },
    [
      onNavigateToPage,
      onImageClick,
      onOpenGallery,
      onUseAsBackground,
      openExternalUrl,
    ],
  );

  const getClickableStyle = (
    target: {
      clickAction?: InfoPanelLinkClickAction;
      targetPageSlug?: string;
      externalUrl?: string;
    },
    baseStyle: React.CSSProperties,
  ): React.CSSProperties => ({
    ...baseStyle,
    cursor: target.clickAction ? 'pointer' : baseStyle.cursor,
  });

  // Fade in animation
  useEffect(() => {
    requestAnimationFrame(() => setIsVisible(true));
  }, []);

  // Keyboard navigation (ESC to close)
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        onClose();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [onClose]);

  // Focus trap
  useEffect(() => {
    const panel = panelRef.current;
    if (!panel) return;

    // Focus the panel on mount
    panel.focus();
  }, []);

  // Drag handling for edit mode
  const handleDragStart = useCallback(
    (e: React.MouseEvent) => {
      if (!isEditMode || !onPanelPositionChange) return;
      e.preventDefault();
      e.stopPropagation();

      const panelX = element.panelXPercent ?? 50;
      const panelY = element.panelYPercent ?? 50;

      dragStartRef.current = {
        x: e.clientX,
        y: e.clientY,
        panelX,
        panelY,
      };
      setIsDragging(true);
    },
    [
      isEditMode,
      onPanelPositionChange,
      element.panelXPercent,
      element.panelYPercent,
    ],
  );

  useEffect(() => {
    if (!isEditMode || !isDragging || !onPanelPositionChange) return;

    const handleMouseMove = (e: MouseEvent) => {
      if (!dragStartRef.current || !containerRef.current) return;

      const container = containerRef.current;
      const rect = container.getBoundingClientRect();

      const deltaX = e.clientX - dragStartRef.current.x;
      const deltaY = e.clientY - dragStartRef.current.y;

      // Convert pixel delta to percentage
      const deltaXPercent = (deltaX / rect.width) * 100;
      const deltaYPercent = (deltaY / rect.height) * 100;

      const newX = Math.max(
        0,
        Math.min(100, dragStartRef.current.panelX + deltaXPercent),
      );
      const newY = Math.max(
        0,
        Math.min(100, dragStartRef.current.panelY + deltaYPercent),
      );

      onPanelPositionChange(newX, newY);
    };

    const handleMouseUp = () => {
      dragStartRef.current = null;
      setIsDragging(false);
    };

    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);

    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseup', handleMouseUp);
    };
  }, [isEditMode, isDragging, onPanelPositionChange]);

  // Handle backdrop click (close when clicking outside panel)
  const handleBackdropClick = useCallback(
    (e: React.MouseEvent) => {
      if (e.target === overlayRef.current && !isEditMode) {
        (onBackdropClose || onClose)();
      }
    },
    [onBackdropClose, onClose, isEditMode],
  );

  // Handle touch on backdrop
  const handleBackdropTouch = useCallback(
    (e: React.TouchEvent) => {
      if (e.target === overlayRef.current && !isEditMode) {
        (onBackdropClose || onClose)();
      }
    },
    [onBackdropClose, onClose, isEditMode],
  );

  // Extract panel styling from element
  const panelXPercent = element.panelXPercent ?? 50;
  const panelYPercent = element.panelYPercent ?? 50;
  const panelWidth = element.panelWidth ?? '400';
  const panelHeight = element.panelHeight ?? 'auto';
  const panelBackgroundColor =
    element.panelBackgroundColor ?? 'rgba(0, 0, 0, 0.85)';
  const panelBorderRadius = element.panelBorderRadius ?? '12';
  const panelBorderWidth = element.panelBorderWidth || '0';
  const panelBorderColor = element.panelBorderColor || '#ffffff';
  const panelBorderStyle = element.panelBorderStyle || 'solid';
  const panelPadding = element.panelPadding ?? '20';
  const panelBackdropBlur = element.panelBackdropBlur ?? '10px';
  const panelTitle = element.panelTitle ?? 'Information';
  const panelText = element.panelText ?? '';
  const panelOverlayColor = element.panelOverlayColor ?? 'rgba(0, 0, 0, 0.3)';

  // Check if overlay should be visible
  const isOverlayVisible =
    panelOverlayColor !== 'transparent' && panelOverlayColor !== 'none';

  // Convert numeric values to canvas units for responsive scaling
  const toCU = (value: string): string => {
    const trimmed = value.trim();
    // Zero doesn't need a unit
    if (trimmed === '0') return '0';
    // Already uses canvas units - return as-is
    if (trimmed.includes('var(--cu') || trimmed.includes('--cu'))
      return trimmed;
    // CSS functions (calc, var, min, max, etc.) - return as-is
    if (/^(calc|var|min|max|clamp)\(/i.test(trimmed)) return trimmed;
    // Already has a unit suffix - return as-is
    if (/[a-z%]+$/i.test(trimmed)) return trimmed;
    // Parse numeric value and convert to canvas units
    const num = parseFloat(trimmed);
    if (!Number.isFinite(num)) return trimmed;
    return `calc(${num} * var(--cu, 1px))`;
  };

  // Panel style with responsive constraints
  const panelStyle: React.CSSProperties = {
    position: 'absolute',
    left: `${panelXPercent}%`,
    top: `${panelYPercent}%`,
    transform: 'translate(-50%, -50%)',
    width:
      panelWidth === 'auto'
        ? 'auto'
        : `min(${toCU(panelWidth)}, calc(100vw - 32px))`,
    maxHeight:
      panelHeight === 'auto'
        ? 'calc(100dvh - 64px)'
        : `min(${toCU(panelHeight)}, calc(100dvh - 64px))`,
    backgroundColor: panelBackgroundColor,
    borderRadius: toCU(panelBorderRadius),
    border:
      panelBorderWidth !== '0' && panelBorderWidth
        ? `${toCU(panelBorderWidth)} ${panelBorderStyle} ${panelBorderColor}`
        : 'none',
    padding: toCU(panelPadding),
    WebkitBackdropFilter: `blur(${panelBackdropBlur})`,
    backdropFilter: `blur(${panelBackdropBlur})`,
    overflowY: 'auto',
    opacity: isVisible ? 1 : 0,
    transition: 'opacity 200ms ease-out',
    // Safe area for notched devices
    paddingTop: `max(${toCU(panelPadding)}, env(safe-area-inset-top))`,
    paddingRight: `max(${toCU(panelPadding)}, env(safe-area-inset-right))`,
    paddingBottom: `max(${toCU(panelPadding)}, env(safe-area-inset-bottom))`,
    paddingLeft: `max(${toCU(panelPadding)}, env(safe-area-inset-left))`,
  };

  return (
    <>
      {/* Backdrop overlay - separate from panel for correct z-index stacking */}
      {renderBackdrop && (
        <div
          ref={overlayRef}
          className='fixed inset-0 z-[51] overflow-hidden'
          style={{
            backgroundColor: isOverlayVisible
              ? panelOverlayColor
              : 'transparent',
            pointerEvents: isEditMode ? 'none' : 'auto',
          }}
          onClick={handleBackdropClick}
          onTouchEnd={handleBackdropTouch}
        />
      )}

      {/* Inner container constrained to canvas bounds */}
      <div
        ref={containerRef}
        className='fixed inset-0 z-[53] overflow-hidden pointer-events-none'
        style={{
          ...cssVars,
          ...(letterboxStyles || { position: 'absolute', inset: 0 }),
        }}
      >
        {/* Info Panel */}
        <div
          ref={panelRef}
          role='dialog'
          aria-modal='true'
          aria-labelledby='info-panel-title'
          tabIndex={-1}
          style={{
            ...panelStyle,
            cursor:
              isEditMode && onPanelPositionChange
                ? isDragging
                  ? 'grabbing'
                  : 'grab'
                : undefined,
            pointerEvents: isEditMode ? 'none' : 'auto',
          }}
          onClick={(e) => e.stopPropagation()}
          onTouchEnd={(e) => e.stopPropagation()}
        >
          {/* Drag handle header (edit mode only) */}
          {isEditMode && onPanelPositionChange && (
            <div
              className='absolute top-0 left-0 right-0 h-8 cursor-grab active:cursor-grabbing rounded-t-xl'
              style={{
                borderRadius: `${toCU(panelBorderRadius)} ${toCU(panelBorderRadius)} 0 0`,
                pointerEvents: 'auto',
              }}
              onMouseDown={handleDragStart}
            >
              {/* Drag indicator dots */}
              <div className='flex items-center justify-center h-full gap-1'>
                <div className='w-8 h-1 rounded-full bg-white/30' />
              </div>
            </div>
          )}

          {/* Close button */}
          <button
            type='button'
            className='absolute top-2 right-2 p-1 rounded-full text-white/70 hover:text-white hover:bg-white/10 transition-colors z-10'
            onClick={onClose}
            aria-label='Close panel'
          >
            <svg
              xmlns='http://www.w3.org/2000/svg'
              fill='none'
              viewBox='0 0 24 24'
              strokeWidth={2}
              stroke='currentColor'
              className='w-5 h-5'
            >
              <path
                strokeLinecap='round'
                strokeLinejoin='round'
                d='M6 18 18 6M6 6l12 12'
              />
            </svg>
          </button>

          {/* Content wrapper - disable pointer events in edit mode for dragging */}
          <div
            style={{
              pointerEvents: isEditMode ? 'none' : 'auto',
              display: 'flex',
              flexDirection: 'column',
              gap: toCU(element.infoPanelSectionGap ?? '12'),
            }}
          >
            {/* Render sections in dynamic order using section instances */}
            {sections.map((section) => {
              switch (section.type) {
                case 'header': {
                  // Header section: use section-level data or fall back to element-level
                  const headerImageUrl =
                    section.headerImageUrl ?? element.infoPanelHeaderImageUrl;
                  const headerText =
                    section.headerText ?? element.infoPanelHeaderText;
                  const headerClickProps = section.clickAction
                    ? {
                        role: 'button' as const,
                        tabIndex: 0,
                        onClick: () => handleLinkDestination(section),
                        onKeyDown: (
                          event: React.KeyboardEvent<HTMLDivElement>,
                        ) => {
                          if (event.key === 'Enter' || event.key === ' ') {
                            event.preventDefault();
                            handleLinkDestination(section);
                          }
                        },
                      }
                    : {};

                  // Image takes priority, otherwise render text
                  if (headerImageUrl) {
                    return (
                      <div
                        key={section.id}
                        {...headerClickProps}
                        style={{
                          ...getClickableStyle(section, headerStyle),
                          padding: 0,
                          overflow: 'hidden',
                        }}
                      >
                        {/* eslint-disable-next-line @next/next/no-img-element */}
                        <img
                          src={resolve(headerImageUrl)}
                          alt=''
                          style={{
                            width: '100%',
                            height: '100%',
                            objectFit: 'cover',
                          }}
                          draggable={false}
                        />
                      </div>
                    );
                  }
                  if (headerText) {
                    return (
                      <div
                        key={section.id}
                        {...headerClickProps}
                        style={getClickableStyle(section, headerStyle)}
                      >
                        {headerText}
                      </div>
                    );
                  }
                  return null;
                }

                case 'title': {
                  // Use section-level title or fall back to element-level
                  const titleContent = section.title ?? panelTitle;
                  if (!titleContent) return null;
                  return (
                    <h2
                      key={section.id}
                      id='info-panel-title'
                      style={{
                        ...getClickableStyle(section, titleStyle),
                        marginTop:
                          isEditMode && onPanelPositionChange
                            ? '16px'
                            : undefined,
                      }}
                      role={section.clickAction ? 'button' : undefined}
                      tabIndex={section.clickAction ? 0 : undefined}
                      onClick={() => handleLinkDestination(section)}
                      onKeyDown={(event) => {
                        if (
                          section.clickAction &&
                          (event.key === 'Enter' || event.key === ' ')
                        ) {
                          event.preventDefault();
                          handleLinkDestination(section);
                        }
                      }}
                    >
                      {titleContent}
                    </h2>
                  );
                }

                case 'text': {
                  // Use section-level text or fall back to element-level
                  const textContent = section.text ?? panelText;
                  if (!textContent) return null;
                  return (
                    <p
                      key={section.id}
                      style={getClickableStyle(section, textStyle)}
                      role={section.clickAction ? 'button' : undefined}
                      tabIndex={section.clickAction ? 0 : undefined}
                      onClick={() => handleLinkDestination(section)}
                      onKeyDown={(event) => {
                        if (
                          section.clickAction &&
                          (event.key === 'Enter' || event.key === ' ')
                        ) {
                          event.preventDefault();
                          handleLinkDestination(section);
                        }
                      }}
                    >
                      {textContent}
                    </p>
                  );
                }

                case 'spans': {
                  // Use section-level spans
                  const sectionSpans = section.spans || [];
                  if (sectionSpans.length === 0) return null;

                  // Build grid style with per-section settings
                  const spanGridStyle = buildInfoPanelSpanGridStyleWithSection(
                    element,
                    section,
                  );

                  return (
                    <div key={section.id} style={spanGridStyle}>
                      {sectionSpans.map((span) => (
                        <button
                          key={span.id}
                          type='button'
                          style={{
                            ...spanStyle,
                            border: 'none',
                            cursor: span.clickAction ? 'pointer' : 'default',
                          }}
                          onClick={() => handleLinkDestination(span)}
                          disabled={!span.clickAction}
                          className='focus:outline-none disabled:cursor-default'
                        >
                          {span.iconUrl ? (
                            /* eslint-disable-next-line @next/next/no-img-element */
                            <img
                              src={resolve(span.iconUrl)}
                              alt={span.text || ''}
                              style={{
                                width: '1em',
                                height: '1em',
                                objectFit: 'contain',
                              }}
                              draggable={false}
                            />
                          ) : (
                            span.text
                          )}
                        </button>
                      ))}
                    </div>
                  );
                }

                case 'cards': {
                  // Use section-level images
                  const sectionImages = section.images || [];
                  if (sectionImages.length === 0) return null;

                  // Build grid style with per-section settings
                  const cardGridStyle = buildInfoPanelCardGridStyleWithSection(
                    element,
                    section,
                  );

                  return (
                    <div key={section.id} style={cardGridStyle}>
                      {sectionImages.map((image) => (
                        <button
                          key={image.id}
                          type='button'
                          style={{
                            ...cardStyle,
                            display: 'block', // Needed for aspectRatio to work on buttons
                            position: 'relative',
                            cursor: 'pointer',
                            border: 'none',
                            padding: 0,
                            overflow: 'hidden', // Respect borderRadius on children
                          }}
                          className='focus:outline-none'
                          onClick={() =>
                            handleImageDestination(
                              image,
                              section,
                              sectionImages,
                            )
                          }
                          aria-label={image.caption || 'View image'}
                        >
                          {image.itemType === '360' ? (
                            // Embed placeholder - shows globe icon
                            <div className='w-full h-full flex flex-col items-center justify-center text-white/60'>
                              <svg
                                xmlns='http://www.w3.org/2000/svg'
                                fill='none'
                                viewBox='0 0 24 24'
                                strokeWidth={1.5}
                                stroke='currentColor'
                                className='w-8 h-8 mb-1'
                              >
                                <path
                                  strokeLinecap='round'
                                  strokeLinejoin='round'
                                  d='M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5a17.92 17.92 0 0 1-8.716-4.247m0 0A8.966 8.966 0 0 1 3 12c0-1.97.633-3.79 1.706-5.27'
                                />
                              </svg>
                              <span className='text-xs'>360/Embed</span>
                            </div>
                          ) : image.itemType === 'video' && image.videoUrl ? (
                            <VideoThumbnail
                              src={resolve(image.videoUrl)}
                              caption={image.caption}
                            />
                          ) : image.itemType === 'video' ? (
                            <div className='w-full h-full flex flex-col items-center justify-center text-white/60'>
                              <svg
                                xmlns='http://www.w3.org/2000/svg'
                                fill='none'
                                viewBox='0 0 24 24'
                                strokeWidth={1.5}
                                stroke='currentColor'
                                className='w-8 h-8 mb-1'
                              >
                                <path
                                  strokeLinecap='round'
                                  strokeLinejoin='round'
                                  d='m5.25 5.653 8.954 5.722a.75.75 0 0 1 0 1.25L5.25 18.347A.75.75 0 0 1 4.125 17.722V6.278a.75.75 0 0 1 1.125-.625Z'
                                />
                              </svg>
                              <span className='text-xs'>Video</span>
                            </div>
                          ) : image.imageUrl ? (
                            // Regular image thumbnail
                            // eslint-disable-next-line @next/next/no-img-element
                            <img
                              src={resolve(image.imageUrl)}
                              alt={image.caption || ''}
                              style={{
                                width: '100%',
                                height: '100%',
                                objectFit: 'cover',
                              }}
                              draggable={false}
                            />
                          ) : (
                            // Empty placeholder
                            <div className='w-full h-full flex items-center justify-center text-white/40'>
                              <svg
                                xmlns='http://www.w3.org/2000/svg'
                                fill='none'
                                viewBox='0 0 24 24'
                                strokeWidth={1.5}
                                stroke='currentColor'
                                className='w-8 h-8'
                              >
                                <path
                                  strokeLinecap='round'
                                  strokeLinejoin='round'
                                  d='m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z'
                                />
                              </svg>
                            </div>
                          )}

                          {/* Card title overlay */}
                          {image.caption && (
                            <span
                              style={{
                                ...cardTitleStyle,
                                position: 'absolute',
                                bottom: 0,
                                left: 0,
                                right: 0,
                              }}
                            >
                              {image.caption}
                            </span>
                          )}
                        </button>
                      ))}
                    </div>
                  );
                }

                case 'images': {
                  // Use section-level images
                  const sectionImages = section.images || [];

                  // Nothing to show if no items
                  if (sectionImages.length === 0) return null;

                  // Build grid style with per-section settings
                  const gridStyle = buildInfoPanelCardGridStyleWithSection(
                    element,
                    section,
                  );

                  // Thumbnail style for grid items
                  const thumbnailStyle: React.CSSProperties = {
                    ...cardStyle,
                    display: 'block',
                    width: '100%',
                    cursor: 'pointer',
                    border: 'none',
                    padding: 0,
                    overflow: 'hidden',
                  };

                  return (
                    <div
                      key={section.id}
                      className='images-section'
                      style={{
                        display: 'flex',
                        flexDirection: 'column',
                        gap: gridStyle.gap || 'calc(8 * var(--cu, 1px))',
                      }}
                    >
                      {/* Thumbnail Grid */}
                      <div style={gridStyle}>
                        {sectionImages.map((img) => {
                          const itemType = img.itemType || 'image';
                          const is360 = itemType === '360';
                          const isVideo = itemType === 'video';

                          return (
                            <button
                              key={img.id}
                              type='button'
                              style={thumbnailStyle}
                              className={
                                is360
                                  ? 'trigger-360 focus:outline-none'
                                  : isVideo
                                    ? 'trigger-video focus:outline-none'
                                    : 'transition-opacity hover:opacity-100 focus:outline-none'
                              }
                              onClick={() => {
                                if (!isVideo && !is360) {
                                  onSelectImage?.(img.id);
                                }
                                handleImageDestination(
                                  img,
                                  section,
                                  sectionImages,
                                );
                              }}
                              aria-label={
                                is360
                                  ? active360ItemId === img.id
                                    ? 'Close 360° view'
                                    : 'Open 360° view'
                                  : img.caption ||
                                    (isVideo ? 'Open video' : 'Select image')
                              }
                              aria-pressed={
                                is360 ? active360ItemId === img.id : undefined
                              }
                            >
                              {is360 ? (
                                img.iconUrl ? (
                                  // eslint-disable-next-line @next/next/no-img-element
                                  <img
                                    src={resolve(img.iconUrl)}
                                    alt='360°'
                                    style={{
                                      width: '100%',
                                      height: '100%',
                                      objectFit: 'contain',
                                    }}
                                    draggable={false}
                                  />
                                ) : (
                                  <div className='w-full h-full flex flex-col items-center justify-center text-white/60'>
                                    <svg
                                      xmlns='http://www.w3.org/2000/svg'
                                      fill='none'
                                      viewBox='0 0 24 24'
                                      strokeWidth={1.5}
                                      stroke='currentColor'
                                      className='w-8 h-8 mb-1'
                                    >
                                      <path
                                        strokeLinecap='round'
                                        strokeLinejoin='round'
                                        d='M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5a17.92 17.92 0 0 1-8.716-4.247m0 0A8.966 8.966 0 0 1 3 12c0-1.97.633-3.79 1.706-5.27'
                                      />
                                    </svg>
                                    <span className='text-xs'>360°</span>
                                  </div>
                                )
                              ) : isVideo ? (
                                img.videoUrl ? (
                                  <VideoThumbnail
                                    src={resolve(img.videoUrl)}
                                    caption={img.caption}
                                  />
                                ) : (
                                  <div className='w-full h-full flex flex-col items-center justify-center text-white/60'>
                                    <svg
                                      xmlns='http://www.w3.org/2000/svg'
                                      fill='none'
                                      viewBox='0 0 24 24'
                                      strokeWidth={1.5}
                                      stroke='currentColor'
                                      className='w-8 h-8 mb-1'
                                    >
                                      <path
                                        strokeLinecap='round'
                                        strokeLinejoin='round'
                                        d='m5.25 5.653 8.954 5.722a.75.75 0 0 1 0 1.25L5.25 18.347A.75.75 0 0 1 4.125 17.722V6.278a.75.75 0 0 1 1.125-.625Z'
                                      />
                                    </svg>
                                    <span className='text-xs'>Video</span>
                                  </div>
                                )
                              ) : img.imageUrl ? (
                                // eslint-disable-next-line @next/next/no-img-element
                                <img
                                  src={resolve(img.imageUrl)}
                                  alt=''
                                  style={{
                                    width: '100%',
                                    height: '100%',
                                    objectFit: 'cover',
                                  }}
                                  draggable={false}
                                />
                              ) : (
                                <div className='w-full h-full flex items-center justify-center text-white/40'>
                                  <svg
                                    xmlns='http://www.w3.org/2000/svg'
                                    fill='none'
                                    viewBox='0 0 24 24'
                                    strokeWidth={1.5}
                                    stroke='currentColor'
                                    className='w-6 h-6'
                                  >
                                    <path
                                      strokeLinecap='round'
                                      strokeLinejoin='round'
                                      d='m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z'
                                    />
                                  </svg>
                                </div>
                              )}
                            </button>
                          );
                        })}
                      </div>
                    </div>
                  );
                }

                default:
                  return null;
              }
            })}
          </div>
        </div>
      </div>
    </>
  );
};

export default InfoPanelOverlay;
