/**
 * CarouselElement Component
 *
 * Carousel element - slideshow of images with navigation.
 * Supports two modes:
 * - Normal: inline carousel with prev/next navigation
 * - Full-width: covers full viewport as background layer (z-10)
 *   Other elements can be positioned above the carousel
 *
 * Full-width mode features:
 * - Arrow key navigation (ArrowLeft/ArrowRight)
 * - Touch swipe support
 * - Draggable button positioning (constructor edit mode)
 * - Navigation-style rendering when custom icons with dimensions are set
 */

import React, {
  useState,
  useMemo,
  useCallback,
  useEffect,
  useRef,
} from 'react';
import { createPortal } from 'react-dom';
import type { CSSProperties } from 'react';
import Icon from '@mdi/react';
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
import type { CanvasElement, CarouselSlide } from '../../../types/constructor';
import { resolveAssetPlaybackUrl } from '../../../lib/assetUrl';
import { getFontByKey, getFontStyle } from '../../../lib/fonts';

interface CarouselElementProps {
  element: CanvasElement;
  resolveUrl?: (url: string | undefined) => string;
  className: string;
  style: CSSProperties;
  isEditMode?: boolean;
  // Constructor-only: callback when button is dragged to new position
  onButtonPositionChange?: (
    button: 'prev' | 'next',
    x: number,
    y: number,
  ) => void;
}

const clamp = (value: number, min: number, max: number) =>
  Math.min(Math.max(value, min), max);

const CarouselElement: React.FC<CarouselElementProps> = ({
  element,
  resolveUrl,
  className,
  style,
  isEditMode = false,
  onButtonPositionChange,
}) => {
  const resolve = resolveUrl ?? resolveAssetPlaybackUrl;
  const slides: CarouselSlide[] = element.carouselSlides || [];
  const [currentIndex, setCurrentIndex] = useState(0);
  const currentSlide = slides[currentIndex] || slides[0];
  const isFullWidth = element.carouselFullWidth || false;

  // Drag state (constructor edit mode only)
  const [draggingButton, setDraggingButton] = useState<'prev' | 'next' | null>(
    null,
  );
  const [positions, setPositions] = useState({
    prevX: element.carouselPrevX ?? 5,
    prevY: element.carouselPrevY ?? 50,
    nextX: element.carouselNextX ?? 95,
    nextY: element.carouselNextY ?? 50,
  });

  // Touch swipe ref
  const touchStartRef = useRef<{ x: number } | null>(null);
  const overlayRef = useRef<HTMLDivElement>(null);
  const positionsRef = useRef(positions);
  positionsRef.current = positions;

  // Update positions when props change
  useEffect(() => {
    setPositions({
      prevX: element.carouselPrevX ?? 5,
      prevY: element.carouselPrevY ?? 50,
      nextX: element.carouselNextX ?? 95,
      nextY: element.carouselNextY ?? 50,
    });
  }, [
    element.carouselPrevX,
    element.carouselPrevY,
    element.carouselNextX,
    element.carouselNextY,
  ]);

  // Navigation handlers (no event parameter for keyboard/swipe use)
  const goToPrev = useCallback(() => {
    if (slides.length === 0) return;
    setCurrentIndex((prev) => (prev - 1 + slides.length) % slides.length);
  }, [slides.length]);

  const goToNext = useCallback(() => {
    if (slides.length === 0) return;
    setCurrentIndex((prev) => (prev + 1) % slides.length);
  }, [slides.length]);

  // Click handlers for buttons (with event propagation control)
  const handlePrevClick = useCallback(
    (e: React.MouseEvent) => {
      e.stopPropagation();
      if (isEditMode) return;
      goToPrev();
    },
    [goToPrev, isEditMode],
  );

  const handleNextClick = useCallback(
    (e: React.MouseEvent) => {
      e.stopPropagation();
      if (isEditMode) return;
      goToNext();
    },
    [goToNext, isEditMode],
  );

  // Resolve font key to full CSS style (including fontStretch for condensed variants)
  const captionFontStyle = useMemo(() => {
    const fontKey = element.carouselCaptionFontFamily;
    if (!fontKey) return {};
    const font = getFontByKey(fontKey);
    return font ? getFontStyle(font) : { fontFamily: fontKey };
  }, [element.carouselCaptionFontFamily]);

  const showNavigation = slides.length > 1;

  // Track if we're in browser for portal rendering
  const [isMounted, setIsMounted] = useState(false);
  useEffect(() => {
    setIsMounted(true);
  }, []);

  // Arrow key navigation (full-width mode only, runtime only)
  useEffect(() => {
    if (!isFullWidth || isEditMode) return;

    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'ArrowLeft') {
        goToPrev();
      } else if (e.key === 'ArrowRight') {
        goToNext();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [isFullWidth, isEditMode, goToPrev, goToNext]);

  // Touch swipe handling (full-width mode, runtime only)
  const handleTouchStart = useCallback(
    (e: React.TouchEvent) => {
      if (isEditMode) return;
      touchStartRef.current = { x: e.touches[0].clientX };
    },
    [isEditMode],
  );

  const handleTouchEnd = useCallback(
    (e: React.TouchEvent) => {
      if (isEditMode || !touchStartRef.current) return;

      const deltaX = e.changedTouches[0].clientX - touchStartRef.current.x;
      const threshold = 50;

      if (Math.abs(deltaX) > threshold) {
        if (deltaX > 0) {
          goToPrev();
        } else {
          goToNext();
        }
      }

      touchStartRef.current = null;
    },
    [isEditMode, goToPrev, goToNext],
  );

  // Draggable button handling (constructor edit mode only)
  const handleButtonDragStart = useCallback(
    (button: 'prev' | 'next', e: React.MouseEvent) => {
      if (!isEditMode) return;
      e.preventDefault();
      e.stopPropagation();
      setDraggingButton(button);
    },
    [isEditMode],
  );

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

    const handleMove = (e: MouseEvent) => {
      const x = (e.clientX / window.innerWidth) * 100;
      const y = (e.clientY / window.innerHeight) * 100;
      const clampedX = clamp(x, 2, 98);
      const clampedY = clamp(y, 2, 98);

      setPositions((prev) => ({
        ...prev,
        [`${draggingButton}X`]: clampedX,
        // Prev and next buttons share same Y coordinate
        prevY: clampedY,
        nextY: clampedY,
      }));
    };

    const handleUp = () => {
      if (onButtonPositionChange && draggingButton) {
        const current = positionsRef.current;
        onButtonPositionChange(
          draggingButton,
          current[`${draggingButton}X`],
          current[`${draggingButton}Y`],
        );
        // Sync other button's Y position
        if (draggingButton === 'prev') {
          onButtonPositionChange('next', current.nextX, current.prevY);
        } else {
          onButtonPositionChange('prev', current.prevX, current.nextY);
        }
      }
      setDraggingButton(null);
    };

    window.addEventListener('mousemove', handleMove);
    window.addEventListener('mouseup', handleUp);
    return () => {
      window.removeEventListener('mousemove', handleMove);
      window.removeEventListener('mouseup', handleUp);
    };
  }, [isEditMode, draggingButton, onButtonPositionChange]);

  // Convert numeric value to viewport units (vw for width, vh for height)
  const toViewportUnit = (
    value?: string,
    unit: 'vw' | 'vh' = 'vw',
  ): string | undefined => {
    if (!value || value.trim() === '') return undefined;
    const trimmed = value.trim();
    // If value already has a unit, preserve it
    if (/[a-z%]+$/i.test(trimmed)) return trimmed;
    const num = parseFloat(trimmed);
    if (!Number.isFinite(num) || num <= 0) return undefined;
    return `${num}${unit}`;
  };

  // Render navigation button for full-width mode
  const renderNavButton = (
    type: 'prev' | 'next',
    x: number,
    y: number,
    iconUrl?: string,
    defaultIcon?: string,
    buttonWidth?: string,
    buttonHeight?: string,
  ) => {
    const isDragging = draggingButton === type;
    const hasCustomIcon = iconUrl && iconUrl.trim() !== '';
    const widthValue = toViewportUnit(buttonWidth, 'vw');
    const heightValue = toViewportUnit(buttonHeight, 'vh');

    // Navigation-style: custom icon fills button (no backdrop)
    const useNavigationStyle = hasCustomIcon && (widthValue || heightValue);

    return (
      <button
        type='button'
        className={`absolute flex items-center justify-center transition-transform pointer-events-auto ${
          isEditMode
            ? 'cursor-move hover:scale-110'
            : 'cursor-pointer hover:scale-105'
        } ${isDragging ? 'scale-110 z-[60]' : ''}`}
        style={{
          left: `${x}%`,
          top: `${y}%`,
          transform: 'translate(-50%, -50%)',
          ...(widthValue && { width: widthValue }),
          ...(heightValue && { height: heightValue }),
        }}
        onClick={type === 'prev' ? handlePrevClick : handleNextClick}
        onMouseDown={(e) => handleButtonDragStart(type, e)}
      >
        {useNavigationStyle ? (
          // Navigation-style: icon fills button, no backdrop
          // eslint-disable-next-line @next/next/no-img-element
          <img
            src={resolve(iconUrl)}
            alt=''
            style={{ width: '100%', height: '100%', objectFit: 'contain' }}
            draggable={false}
          />
        ) : hasCustomIcon ? (
          // Custom icon without dimensions: fixed size
          // eslint-disable-next-line @next/next/no-img-element
          <img
            src={resolve(iconUrl)}
            alt={type === 'prev' ? 'Previous' : 'Next'}
            className='w-10 h-10 object-contain'
            draggable={false}
          />
        ) : (
          // Default style: MDI icon with backdrop
          <div className='rounded-full bg-black/40 p-3 backdrop-blur-sm'>
            <Icon path={defaultIcon || ''} size={1.5} className='text-white' />
          </div>
        )}
      </button>
    );
  };

  // Full-width carousel - two layers:
  // 1. Background image layer at z-10 (behind canvas elements)
  // 2. Navigation/caption layer at z-30 (above everything for clickability)
  const fullWidthBackground = (
    <div className='fixed inset-0 z-10 overflow-hidden bg-black pointer-events-none'>
      {currentSlide?.imageUrl && (
        // eslint-disable-next-line @next/next/no-img-element
        <img
          src={resolve(currentSlide.imageUrl)}
          alt={currentSlide.caption || 'Carousel slide'}
          className='absolute inset-0 w-full h-full object-cover'
          draggable={false}
        />
      )}
    </div>
  );

  const fullWidthControls = (
    <div
      ref={overlayRef}
      className='fixed inset-0 z-30 pointer-events-none'
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
    >
      {/* Navigation buttons */}
      {showNavigation && (
        <>
          {renderNavButton(
            'prev',
            positions.prevX,
            positions.prevY,
            element.carouselPrevIconUrl,
            mdiChevronLeft,
            element.carouselPrevWidth,
            element.carouselPrevHeight,
          )}
          {renderNavButton(
            'next',
            positions.nextX,
            positions.nextY,
            element.carouselNextIconUrl,
            mdiChevronRight,
            element.carouselNextWidth,
            element.carouselNextHeight,
          )}
        </>
      )}

      {/* Caption */}
      {currentSlide?.caption && (
        <div
          className='absolute bottom-8 left-0 right-0 text-center text-white text-lg px-4'
          style={captionFontStyle}
        >
          {currentSlide.caption}
        </div>
      )}
    </div>
  );

  // Full-width mode: use portal to render outside transform hierarchy
  // Background at z-10, controls at z-30 for clickability
  if (isFullWidth) {
    // SSR safety: only use portal when mounted in browser
    if (!isMounted) {
      return null;
    }

    // In edit mode: render a clickable placeholder so the element can be selected
    // Plus the portal for visual display
    if (isEditMode) {
      return (
        <>
          {/* Clickable placeholder for element selection */}
          <div className={className} style={style}>
            <div className='relative w-full h-full min-w-[120px] min-h-[80px] flex items-center justify-center bg-gray-800/50 rounded border-2 border-dashed border-blue-400'>
              <span className='text-white text-xs px-2 py-1 bg-blue-500 rounded'>
                Full-width Carousel
              </span>
            </div>
          </div>
          {/* Portal for full-screen visual */}
          {createPortal(fullWidthBackground, document.body)}
          {createPortal(fullWidthControls, document.body)}
        </>
      );
    }

    // Runtime mode: render portal only
    return (
      <>
        {createPortal(fullWidthBackground, document.body)}
        {createPortal(fullWidthControls, document.body)}
      </>
    );
  }

  // Normal mode: inline carousel within element dimensions
  return (
    <div className={className} style={style}>
      <div className='relative w-full h-full min-w-[120px] min-h-[80px]'>
        {/* Current slide image */}
        {currentSlide?.imageUrl && (
          // eslint-disable-next-line @next/next/no-img-element
          <img
            src={resolve(currentSlide.imageUrl)}
            alt={currentSlide.caption || 'Carousel slide'}
            className='w-full h-full object-cover rounded'
            draggable={false}
          />
        )}

        {/* Navigation buttons */}
        {showNavigation && (
          <>
            {/* Prev button */}
            <button
              type='button'
              onClick={handlePrevClick}
              className='absolute left-2 top-1/2 -translate-y-1/2 cursor-pointer hover:scale-110 transition-transform'
            >
              {element.carouselPrevIconUrl ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={resolve(element.carouselPrevIconUrl)}
                  alt='Previous'
                  className='w-8 h-8 object-contain'
                  draggable={false}
                />
              ) : (
                <div className='rounded-full bg-black/40 p-2 backdrop-blur-sm'>
                  <Icon path={mdiChevronLeft} size={1} className='text-white' />
                </div>
              )}
            </button>

            {/* Next button */}
            <button
              type='button'
              onClick={handleNextClick}
              className='absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer hover:scale-110 transition-transform'
            >
              {element.carouselNextIconUrl ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={resolve(element.carouselNextIconUrl)}
                  alt='Next'
                  className='w-8 h-8 object-contain'
                  draggable={false}
                />
              ) : (
                <div className='rounded-full bg-black/40 p-2 backdrop-blur-sm'>
                  <Icon
                    path={mdiChevronRight}
                    size={1}
                    className='text-white'
                  />
                </div>
              )}
            </button>
          </>
        )}

        {/* Caption (if present) */}
        {currentSlide?.caption && (
          <div
            className='absolute bottom-4 left-0 right-0 text-center text-white text-sm px-2'
            style={captionFontStyle}
          >
            {currentSlide.caption}
          </div>
        )}
      </div>
    </div>
  );
};

export default CarouselElement;
