'use client';

/**
 * CMS Image Gallery — mirrors Shopware 6 gallery-slider behaviour
 *
 * Config fields (Shopware admin "Element settings"):
 *   displayMode      : 'standard' (Original) | 'cover' (Cropped) | 'contain' (Fixed height)
 *   minHeight        : e.g. '340px'
 *   navigationArrows : 'none' | 'inside' | 'outside'
 *   navigationDots   : 'none' | 'inside' | 'outside'
 *   galleryPosition  : 'left' | 'underneath'   (Preview navigation)
 *   fullScreen       : boolean  — clicking main image opens fullscreen modal
 *   zoom             : boolean  — hover magnifier (not implemented, skipped)
 *   gutter           : number   — gap between slides in px
 *
 * Layout:
 *   galleryPosition='left'       → vertical thumbnail strip on the left
 *   galleryPosition='underneath' → horizontal thumbnail strip below the main image
 *
 * Thumbnail strip is hidden on mobile (md:flex), matching Shopware's
 * responsive: { xs: { enabled: false }, sm: { enabled: false } } config.
 */

import { useState, useCallback, useRef, useEffect } from 'react';
import Image from 'next/image';
import type { CSSProperties } from 'react';

// ─── Types ────────────────────────────────────────────────────────────────────

interface GalleryMedia {
  url?: string;
  width?: number;
  height?: number;
  alt?: string;
  title?: string;
  translated?: { alt?: string; title?: string };
}

interface GalleryItem {
  media?: GalleryMedia;
}

interface CmsElementImageGalleryProps {
  slot: {
    data?: { sliderItems?: GalleryItem[] };
    config?: {
      displayMode?:      { value?: string };
      minHeight?:        { value?: string };
      navigationArrows?: { value?: string };
      navigationDots?:   { value?: string };
      galleryPosition?:  { value?: string }; // 'left' | 'underneath'
      fullScreen?:       { value?: boolean };
      zoom?:             { value?: boolean };
      gutter?:           { value?: number };
      verticalAlign?:    { value?: string };
    };
  };
}

// ─── Thumbnail dimensions ─────────────────────────────────────────────────────

const THUMB_W    = 76;
const THUMB_H    = 57;
const THUMB_GAP  = 4;
const THUMB_STEP = THUMB_W + THUMB_GAP;
const THUMB_STEP_V = THUMB_H + THUMB_GAP;
const THUMBS_VISIBLE_LEFT       = 5;
const THUMBS_VISIBLE_UNDERNEATH = 6;

// ─── Icons ────────────────────────────────────────────────────────────────────

const ChevLeft  = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6"/></svg>;
const ChevRight = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg>;
const ChevUp    = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="18 15 12 9 6 15"/></svg>;
const ChevDown  = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>;
const ExpandIcon = () => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>;
const CloseIcon = () => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>;

// ─── Component ────────────────────────────────────────────────────────────────

export default function CmsElementImageGallery({ slot }: CmsElementImageGalleryProps) {
  const items: GalleryItem[] = slot.data?.sliderItems ?? [];
  const cfg = slot.config ?? {};
  const n = items.length;

  const displayMode  = cfg.displayMode?.value  ?? 'standard';
  const minHeightRaw = cfg.minHeight?.value    ?? '0px';
  const navArrows    = cfg.navigationArrows?.value ?? 'inside';
  const navDots      = cfg.navigationDots?.value   ?? 'none';
  const galleryPos   = cfg.galleryPosition?.value  ?? 'left';
  const fullScreen   = cfg.fullScreen?.value ?? false;

  const isLeft       = galleryPos === 'left';
  const thumbsVisible = isLeft ? THUMBS_VISIBLE_LEFT : THUMBS_VISIBLE_UNDERNEATH;

  // ── Infinite loop — clone technique (1 clone at each end, single-image view) ─
  const cloneN   = n > 1 ? 1 : 0;
  const allItems = n > 1
    ? [...items.slice(-cloneN), ...items, ...items.slice(0, cloneN)]
    : items;
  const total = allItems.length;

  // ── State ─────────────────────────────────────────────────────────────────
  const [realIdx,     setRealIdx]     = useState(0);
  const [pos,         setPos]         = useState(cloneN);
  const [animated,    setAnimated]    = useState(true);
  const [thumbOffset, setThumbOffset] = useState(0);
  const [modalOpen,   setModalOpen]   = useState(false);
  const [dragOffset,  setDragOffset]  = useState(0);

  // ── Refs ──────────────────────────────────────────────────────────────────
  const sliderRef   = useRef<HTMLDivElement>(null);
  const dragStartX  = useRef<number | null>(null);
  const dragCurrX   = useRef<number>(0);
  const isDragging  = useRef(false);
  const posRef      = useRef(pos);      posRef.current    = pos;
  const realIdxRef  = useRef(realIdx);  realIdxRef.current = realIdx;
  const nRef        = useRef(n);        nRef.current      = n;

  const maxThumbOffset = Math.max(0, n - thumbsVisible);

  // Re-enable CSS transition after a no-animation snap
  useEffect(() => {
    if (animated) return;
    const id = requestAnimationFrame(() => requestAnimationFrame(() => setAnimated(true)));
    return () => cancelAnimationFrame(id);
  }, [animated]);

  // Snap back to real position after sliding into a clone
  const handleTransitionEnd = useCallback(() => {
    if (cloneN === 0) return;
    const p = posRef.current;
    if (p < cloneN) {
      setAnimated(false);
      setPos(p + nRef.current);
    } else if (p >= cloneN + nRef.current) {
      setAnimated(false);
      setPos(p - nRef.current);
    }
  }, [cloneN]);

  // ── Thumbnail auto-scroll helper ──────────────────────────────────────────
  const scrollThumbTo = useCallback((idx: number) => {
    setThumbOffset(prev => {
      if (idx < prev)                        return idx;
      if (idx >= prev + thumbsVisible)       return Math.min(idx - thumbsVisible + 1, maxThumbOffset);
      return prev;
    });
  }, [thumbsVisible, maxThumbOffset]);

  // ── Navigation ────────────────────────────────────────────────────────────
  const goTo = useCallback((idx: number) => {
    setRealIdx(idx);
    setAnimated(true);
    setPos(cloneN + idx);
    scrollThumbTo(idx);
  }, [cloneN, scrollThumbTo]);

  const prev = useCallback(() => {
    const newReal = ((realIdxRef.current - 1) + nRef.current) % nRef.current;
    setRealIdx(newReal);
    setAnimated(true);
    setPos(cloneN + realIdxRef.current - 1);
    scrollThumbTo(newReal);
  }, [cloneN, scrollThumbTo]);

  const next = useCallback(() => {
    const newReal = (realIdxRef.current + 1) % nRef.current;
    setRealIdx(newReal);
    setAnimated(true);
    setPos(cloneN + realIdxRef.current + 1);
    scrollThumbTo(newReal);
  }, [cloneN, scrollThumbTo]);

  const thumbPrev = useCallback(() => setThumbOffset(o => Math.max(0, o - 1)), []);
  const thumbNext = useCallback(() => setThumbOffset(o => Math.min(o + 1, maxThumbOffset)), [maxThumbOffset]);

  // ── Drag / swipe ──────────────────────────────────────────────────────────
  const DRAG_THRESHOLD = 50;

  const onDragStart = (clientX: number) => {
    dragStartX.current = clientX;
    dragCurrX.current  = clientX;
    isDragging.current = false;
  };
  const onDragMove = (clientX: number) => {
    if (dragStartX.current === null) return;
    const delta = clientX - dragStartX.current;
    if (!isDragging.current && Math.abs(delta) > 5) isDragging.current = true;
    if (isDragging.current) { dragCurrX.current = clientX; setDragOffset(delta); }
  };
  const onDragEnd = () => {
    if (dragStartX.current === null) return;
    const delta = dragCurrX.current - dragStartX.current;
    dragStartX.current = null;
    setDragOffset(0);
    if (!isDragging.current) return;
    const w = sliderRef.current?.offsetWidth ?? 300;
    if      (delta < -Math.min(DRAG_THRESHOLD, w * 0.1)) next();
    else if (delta >  Math.min(DRAG_THRESHOLD, w * 0.1)) prev();
    isDragging.current = false;
  };

  // ── Keyboard in modal ─────────────────────────────────────────────────────
  useEffect(() => {
    if (!modalOpen) return;
    const handler = (e: KeyboardEvent) => {
      if (e.key === 'Escape')     setModalOpen(false);
      if (e.key === 'ArrowLeft')  prev();
      if (e.key === 'ArrowRight') next();
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [modalOpen, prev, next]);

  if (n === 0) return null;

  // ── Display mode ──────────────────────────────────────────────────────────
  const isCover   = displayMode === 'cover';
  const isContain = displayMode === 'contain';
  const hasMinH   = minHeightRaw && minHeightRaw !== '0px';
  const mainH     = (isCover || isContain) ? (hasMinH ? minHeightRaw : '400px') : undefined;
  const minH      = !mainH && hasMinH ? minHeightRaw : undefined;

  const showArrows = navArrows !== 'none' && n > 1;
  const showDots   = navDots   !== 'none' && n > 1;
  const arrowOut   = navArrows === 'outside';
  const dotOut     = navDots   === 'outside';

  // ── Render: single image ──────────────────────────────────────────────────
  const renderImage = (media: GalleryMedia | undefined, priority = false) => {
    if (!media?.url) return null;
    const alt = media.translated?.alt ?? media.alt ?? '';
    if (isCover || isContain) {
      return (
        <Image
          src={media.url}
          alt={alt}
          fill
          className={isCover ? 'object-cover' : 'object-contain'}
          sizes="(max-width: 768px) 100vw, 800px"
          priority={priority}
        />
      );
    }
    return (
      <Image
        src={media.url}
        alt={alt}
        width={media.width ?? 1200}
        height={media.height ?? 800}
        className="w-full h-auto block"
        sizes="(max-width: 768px) 100vw, 800px"
        priority={priority}
      />
    );
  };

  // ── Thumbnail strip ───────────────────────────────────────────────────────
  const renderThumbnails = () => {
    if (n <= 1) return null;

    const canBack = thumbOffset > 0;
    const canFwd  = thumbOffset < maxThumbOffset;
    const btnBase = 'flex items-center justify-center text-surface-600 hover:text-brand-600 disabled:opacity-20 transition';

    if (isLeft) {
      const viewportH = thumbsVisible * THUMB_STEP_V - THUMB_GAP;
      return (
        <div className="hidden md:flex flex-col items-center gap-1 mr-3 flex-none" style={{ width: `${THUMB_W}px` }}>
          <button onClick={thumbPrev} disabled={!canBack} aria-label="Previous thumbnails"
            className={`${btnBase} w-full h-6`}>
            <ChevUp />
          </button>

          <div className="overflow-hidden w-full" style={{ height: `${viewportH}px` }}>
            <div
              className="flex flex-col gap-1"
              style={{
                transform: `translateY(${-thumbOffset * THUMB_STEP_V}px)`,
                transition: 'transform 0.3s ease',
              }}
            >
              {items.map((item, idx) => (
                <button
                  key={idx}
                  onClick={() => goTo(idx)}
                  aria-label={`View image ${idx + 1}`}
                  className={`flex-none rounded overflow-hidden border-2 transition w-full ${
                    idx === realIdx
                      ? 'border-brand-600'
                      : 'border-transparent hover:border-surface-300'
                  }`}
                  style={{ height: `${THUMB_H}px` }}
                >
                  {item.media?.url && (
                    <div className="relative w-full h-full">
                      <Image
                        src={item.media.url}
                        alt={item.media.translated?.alt ?? item.media.alt ?? ''}
                        fill
                        className="object-cover"
                        sizes={`${THUMB_W}px`}
                      />
                    </div>
                  )}
                </button>
              ))}
            </div>
          </div>

          <button onClick={thumbNext} disabled={!canFwd} aria-label="Next thumbnails"
            className={`${btnBase} w-full h-6`}>
            <ChevDown />
          </button>
        </div>
      );
    }

    // Underneath: horizontal strip
    return (
      <div className="hidden md:flex items-center gap-1 mt-2">
        <button onClick={thumbPrev} disabled={!canBack} aria-label="Previous thumbnails"
          className={`${btnBase} flex-none w-6 h-6`}>
          <ChevLeft />
        </button>

        <div className="overflow-hidden flex-1" style={{ height: `${THUMB_H}px` }}>
          <div
            className="flex gap-1"
            style={{
              transform: `translateX(${-thumbOffset * THUMB_STEP}px)`,
              transition: 'transform 0.3s ease',
              width: `${n * THUMB_STEP - THUMB_GAP}px`,
            }}
          >
            {items.map((item, idx) => (
              <button
                key={idx}
                onClick={() => goTo(idx)}
                aria-label={`View image ${idx + 1}`}
                className={`flex-none rounded overflow-hidden border-2 transition ${
                  idx === realIdx
                    ? 'border-brand-600'
                    : 'border-transparent hover:border-surface-300'
                }`}
                style={{ width: `${THUMB_W}px`, height: `${THUMB_H}px` }}
              >
                {item.media?.url && (
                  <div className="relative w-full h-full">
                    <Image
                      src={item.media.url}
                      alt={item.media.translated?.alt ?? item.media.alt ?? ''}
                      fill
                      className="object-cover"
                      sizes={`${THUMB_W}px`}
                    />
                  </div>
                )}
              </button>
            ))}
          </div>
        </div>

        <button onClick={thumbNext} disabled={!canFwd} aria-label="Next thumbnails"
          className={`${btnBase} flex-none w-6 h-6`}>
          <ChevRight />
        </button>
      </div>
    );
  };

  // ── Main slider ───────────────────────────────────────────────────────────
  const renderMainSlider = () => {
    const arrowBtnInside  = 'absolute top-1/2 -translate-y-1/2 z-10 flex items-center justify-center w-9 h-9 rounded-full bg-white/90 hover:bg-white shadow-md text-surface-800 disabled:opacity-30 transition';
    const arrowBtnOutside = 'absolute top-1/2 -translate-y-1/2 z-10 flex items-center justify-center w-9 h-9 rounded-full bg-white hover:bg-surface-100 shadow border border-surface-200 text-surface-800 disabled:opacity-30 transition';

    return (
      <div className={`relative flex-1 min-w-0 ${arrowOut && showArrows ? 'px-10' : ''}`}>
        {/* Viewport */}
        <div
          ref={sliderRef}
          className="overflow-hidden w-full rounded-xl select-none"
          style={{
            cursor: n > 1 ? (dragOffset !== 0 ? 'grabbing' : 'grab') : 'default',
            ...(mainH ? { height: mainH } : {}),
            ...(minH  ? { minHeight: minH } : {}),
          }}
          onMouseDown={(e) => onDragStart(e.clientX)}
          onMouseMove={(e) => onDragMove(e.clientX)}
          onMouseUp={onDragEnd}
          onMouseLeave={() => { if (dragStartX.current !== null) onDragEnd(); }}
          onTouchStart={(e) => onDragStart(e.touches[0].clientX)}
          onTouchMove={(e) => { e.preventDefault(); onDragMove(e.touches[0].clientX); }}
          onTouchEnd={onDragEnd}
          onClickCapture={(e) => { if (isDragging.current) e.stopPropagation(); }}
        >
          {/* Sliding track — 1 slide at a time, with clones for infinite loop */}
          <div
            className={`flex ${mainH ? 'h-full' : ''}`}
            style={{
              width: `${total * 100}%`,
              transform: `translateX(calc(${-(pos / total) * 100}% + ${dragOffset}px))`,
              transition: dragOffset !== 0 ? 'none' : animated ? 'transform 0.4s ease' : 'none',
            }}
            onTransitionEnd={handleTransitionEnd}
          >
            {allItems.map((item, idx) => (
              <div
                key={idx}
                className={`relative ${mainH ? 'h-full' : ''}`}
                style={{ width: `${100 / total}%`, flexShrink: 0 }}
                onClick={() => { if (!isDragging.current && fullScreen) setModalOpen(true); }}
              >
                {renderImage(item.media, idx === cloneN)}
              </div>
            ))}
          </div>
        </div>

        {/* Fullscreen button */}
        {fullScreen && (
          <button
            onClick={() => setModalOpen(true)}
            className="absolute top-2 right-2 z-10 flex items-center justify-center w-8 h-8 rounded-full bg-black/40 hover:bg-black/60 text-white transition"
            aria-label="Open fullscreen"
          >
            <ExpandIcon />
          </button>
        )}

        {/* Inside arrows */}
        {showArrows && !arrowOut && (
          <>
            <button onClick={prev} aria-label="Previous" className={`${arrowBtnInside} left-2`}><ChevLeft /></button>
            <button onClick={next} aria-label="Next"     className={`${arrowBtnInside} right-2`}><ChevRight /></button>
          </>
        )}

        {/* Outside arrows */}
        {showArrows && arrowOut && (
          <>
            <button onClick={prev} aria-label="Previous" className={`${arrowBtnOutside} left-0`}><ChevLeft /></button>
            <button onClick={next} aria-label="Next"     className={`${arrowBtnOutside} right-0`}><ChevRight /></button>
          </>
        )}

        {/* Inside dots */}
        {showDots && !dotOut && (
          <div className="absolute bottom-3 left-1/2 -translate-x-1/2 z-10 flex gap-1.5">
            {items.map((_, i) => (
              <button key={i} onClick={() => goTo(i)} aria-label={`Slide ${i + 1}`}
                className={`h-2 rounded-full transition-all ${i === realIdx ? 'bg-white w-5' : 'bg-white/50 hover:bg-white/80 w-2'}`} />
            ))}
          </div>
        )}
      </div>
    );
  };

  // ── Fullscreen modal ──────────────────────────────────────────────────────
  const renderModal = () => {
    if (!fullScreen || !modalOpen) return null;
    const media = items[realIdx]?.media;
    return (
      <div
        className="fixed inset-0 z-50 bg-black/95 flex flex-col"
        role="dialog"
        aria-modal="true"
        aria-label="Image fullscreen view"
      >
        <button
          onClick={() => setModalOpen(false)}
          className="absolute top-4 right-4 z-10 flex items-center justify-center w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 text-white transition"
          aria-label="Close"
        >
          <CloseIcon />
        </button>

        <div className="flex-1 flex items-center justify-center p-8 min-h-0">
          {media?.url && (
            <Image
              src={media.url}
              alt={media.translated?.alt ?? media.alt ?? ''}
              width={media.width ?? 1600}
              height={media.height ?? 1200}
              className="max-w-full max-h-full object-contain"
              sizes="100vw"
              priority
            />
          )}
        </div>

        {n > 1 && (
          <>
            <button onClick={prev} aria-label="Previous"
              className="absolute left-4 top-1/2 -translate-y-1/2 flex items-center justify-center w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 text-white transition">
              <ChevLeft />
            </button>
            <button onClick={next} aria-label="Next"
              className="absolute right-4 top-1/2 -translate-y-1/2 flex items-center justify-center w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 text-white transition">
              <ChevRight />
            </button>
          </>
        )}

        {n > 1 && (
          <div className="flex justify-center gap-2 pb-4 px-4 flex-none">
            {items.map((item, idx) => (
              <button
                key={idx}
                onClick={() => goTo(idx)}
                className={`rounded overflow-hidden border-2 transition flex-none ${idx === realIdx ? 'border-white' : 'border-transparent opacity-40 hover:opacity-70'}`}
                style={{ width: '60px', height: '45px' }}
                aria-label={`Go to image ${idx + 1}`}
              >
                {item.media?.url && (
                  <div className="relative w-full h-full">
                    <Image src={item.media.url} alt="" fill className="object-cover" sizes="60px" />
                  </div>
                )}
              </button>
            ))}
          </div>
        )}
      </div>
    );
  };

  // ── Layout ────────────────────────────────────────────────────────────────
  return (
    <div className="w-full" role="region" aria-label={`Image gallery, ${n} images`}>
      <div className={`flex ${isLeft ? 'flex-row items-start' : 'flex-col'}`}>
        {isLeft && renderThumbnails()}
        {renderMainSlider()}
      </div>

      {showDots && dotOut && (
        <div className="flex justify-center gap-1.5 mt-3">
          {items.map((_, i) => (
            <button key={i} onClick={() => goTo(i)} aria-label={`Slide ${i + 1}`}
              className={`h-2 rounded-full transition-all ${i === realIdx ? 'bg-brand-600 w-5' : 'bg-surface-300 hover:bg-surface-400 w-2'}`} />
          ))}
        </div>
      )}

      {!isLeft && renderThumbnails()}
      {renderModal()}
    </div>
  );
}
