'use client';

/**
 * CMS Image Slider — mirrors Shopware 6 tiny-slider behaviour
 *
 * Infinite loop via the clone technique:
 *   [last N clones] [real items] [first N clones]
 * When the user slides into a clone zone, we snap (without animation)
 * to the matching real position — exactly what tiny-slider does.
 *
 * Config fields (from Shopware admin "Element settings"):
 *   displayMode       : 'standard' (Original) | 'cover' (Cropped) | 'contain' (Fixed height)
 *   minHeight         : e.g. '300px'
 *   verticalAlign     : '' | 'flex-start' | 'center' | 'flex-end'
 *   navigationArrows  : 'none' | 'inside' | 'outside'
 *   navigationDots    : 'none' | 'inside' | 'outside'
 *   speed             : animation duration in ms (default 300)
 *   autoSlide         : boolean
 *   autoplayTimeout   : ms between slides (default 5000)
 */

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

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

interface SliderItem {
  media?: {
    url?: string;
    width?: number;
    height?: number;
    alt?: string;
    title?: string;
    translated?: { alt?: string; title?: string };
  };
  url?: string;
  newTab?: boolean;
}

interface CmsElementImageSliderProps {
  slot: {
    data?: { sliderItems?: SliderItem[] };
    config?: {
      navigationArrows?: { value?: string };
      navigationDots?:   { value?: string };
      autoSlide?:        { value?: boolean };
      autoplayTimeout?:  { value?: number };
      speed?:            { value?: number };
      displayMode?:      { value?: string };
      minHeight?:        { value?: string };
      verticalAlign?:    { value?: string };
    };
  };
}

// ─── Responsive visible item count (matches Shopware tiny-slider defaults) ────

function useVisibleItems(): number {
  const [count, setCount] = useState(4); // SSR default: desktop = 4
  useEffect(() => {
    const update = () => {
      if      (window.innerWidth < 640)  setCount(1);
      else if (window.innerWidth < 1024) setCount(2);
      else                               setCount(4);
    };
    update();
    window.addEventListener('resize', update);
    return () => window.removeEventListener('resize', update);
  }, []);
  return count;
}

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

const ChevronLeft  = () => <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 ChevronRight = () => <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>;

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

export default function CmsElementImageSlider({ slot }: CmsElementImageSliderProps) {
  const realItems: SliderItem[] = slot.data?.sliderItems ?? [];
  const cfg = slot.config ?? {};
  const n = realItems.length;

  // Read config values
  const navArrows      = cfg.navigationArrows?.value ?? 'inside';
  const navDots        = cfg.navigationDots?.value   ?? 'inside';
  const autoSlide      = cfg.autoSlide?.value        ?? false;
  const autoplayMs     = cfg.autoplayTimeout?.value  ?? 5000;
  const speedMs        = cfg.speed?.value            ?? 300;
  const displayMode    = cfg.displayMode?.value      ?? 'standard';
  const minHeightRaw   = cfg.minHeight?.value        ?? '0px';
  const verticalAlign  = cfg.verticalAlign?.value    ?? '';

  const visibleItems = useVisibleItems();

  // Infinite loop only makes sense when there are more items than visible slots
  const canLoop   = n > visibleItems;
  const cloneN    = canLoop ? visibleItems : 0;

  // Build the extended items array: [clonesBefore | real | clonesAfter]
  const allItems = canLoop
    ? [...realItems.slice(-cloneN), ...realItems, ...realItems.slice(0, cloneN)]
    : realItems;
  const total = allItems.length;

  // ── State ──────────────────────────────────────────────────────────────────
  // realIdx  : logical slide index (0 … n-1), used for dots highlight
  // pos      : index into allItems used for CSS translateX
  // animated : whether the CSS transition is enabled (disabled during snap)
  const [realIdx,  setRealIdx]  = useState(0);
  const [pos,      setPos]      = useState(cloneN);   // starts after clonesBefore
  const [animated, setAnimated] = useState(true);

  // Stable refs so callbacks always see current values without stale closures
  const posRef          = useRef(pos);   posRef.current       = pos;
  const realIdxRef      = useRef(realIdx); realIdxRef.current = realIdx;
  const cloneNRef       = useRef(cloneN);  cloneNRef.current  = cloneN;
  const nRef            = useRef(n);       nRef.current       = n;
  const visibleRef      = useRef(visibleItems); visibleRef.current = visibleItems;
  const canLoopRef      = useRef(canLoop);  canLoopRef.current = canLoop;
  const prevVisibleRef  = useRef(visibleItems);

  // ── Re-sync position when screen resizes (visibleItems changes) ────────────
  useEffect(() => {
    if (prevVisibleRef.current === visibleItems) return;
    prevVisibleRef.current = visibleItems;
    // Rebuild clone offset without animation
    const newCloneN = visibleItems < nRef.current ? visibleItems : 0;
    setAnimated(false);
    setPos(newCloneN + realIdxRef.current);
  }, [visibleItems]);

  // Re-enable animation after a snap (needs two rAF ticks to skip paint)
  useEffect(() => {
    if (animated) return;
    const id = requestAnimationFrame(() => requestAnimationFrame(() => setAnimated(true)));
    return () => cancelAnimationFrame(id);
  }, [animated]);

  // ── Snap after sliding into clone zone ────────────────────────────────────
  const handleTransitionEnd = useCallback(() => {
    if (!canLoopRef.current) return;
    const p      = posRef.current;
    const cn     = cloneNRef.current;
    const count  = nRef.current;
    if (p < cn) {
      setAnimated(false);
      setPos(p + count);
    } else if (p >= cn + count) {
      setAnimated(false);
      setPos(p - count);
    }
  }, []);

  // ── Navigation ─────────────────────────────────────────────────────────────
  const prev = useCallback(() => {
    const newReal = realIdxRef.current - 1;
    const wrapped = ((newReal % nRef.current) + nRef.current) % nRef.current;
    setRealIdx(wrapped);
    setAnimated(true);
    if (canLoopRef.current) {
      // Goes one step into clonesBefore when newReal < 0
      setPos(cloneNRef.current + newReal);
    } else {
      setPos(p => Math.max(0, p - 1));
    }
  }, []);

  const next = useCallback(() => {
    const newReal = realIdxRef.current + 1;
    const wrapped = newReal % nRef.current;
    setRealIdx(wrapped);
    setAnimated(true);
    if (canLoopRef.current) {
      // Goes one step into clonesAfter when newReal >= n
      setPos(cloneNRef.current + newReal);
    } else {
      setPos(p => Math.min(p + 1, nRef.current - visibleRef.current));
    }
  }, []);

  const goTo = useCallback((idx: number) => {
    setRealIdx(idx);
    setAnimated(true);
    setPos(cloneNRef.current + idx);
  }, []);

  // ── Autoplay ───────────────────────────────────────────────────────────────
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
  useEffect(() => {
    if (!autoSlide) return;
    intervalRef.current = setInterval(next, autoplayMs);
    return () => { if (intervalRef.current) clearInterval(intervalRef.current); };
  }, [autoSlide, autoplayMs, next]);

  if (n === 0) return null;

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

  // ── Vertical alignment (for 'standard' mode with mixed-height images) ─────
  const vAlign =
    verticalAlign === 'center'   ? 'items-center' :
    verticalAlign === 'flex-end' ? 'items-end'    : 'items-start';

  // ── Track translate ───────────────────────────────────────────────────────
  const trackW     = `${(total / visibleItems) * 100}%`;
  const translateX = `${-(pos / total) * 100}%`;

  const showArrows   = navArrows !== 'none';
  const showDots     = navDots   !== 'none' && n > 1;
  const arrowOut     = navArrows === 'outside';
  const dotOut       = navDots   === 'outside';
  const atStart      = !canLoop && pos === 0;
  const atEnd        = !canLoop && pos >= n - visibleItems;

  const arrowBtnBase = 'flex items-center justify-center w-9 h-9 rounded-full transition disabled:opacity-30 disabled:cursor-default';
  const arrowInside  = `${arrowBtnBase} absolute top-1/2 -translate-y-1/2 z-10 bg-white/90 hover:bg-white shadow-md text-surface-800`;
  const arrowOutside = `${arrowBtnBase} absolute top-1/2 -translate-y-1/2 z-10 bg-white hover:bg-surface-100 shadow border border-surface-200 text-surface-800`;

  return (
    <div className="relative w-full">
      {/* Pad sides when arrows are outside (like Shopware's has-nav-outside) */}
      <div className={arrowOut && showArrows ? 'px-10' : ''}>

        {/* ── Overflow viewport ──────────────────────────────────────────── */}
        <div className="overflow-hidden w-full">
          <div
            className={`flex ${vAlign}`}
            style={{
              width: trackW,
              transform: `translateX(${translateX})`,
              transition: animated ? `transform ${speedMs}ms ease` : 'none',
            }}
            onTransitionEnd={handleTransitionEnd}
          >
            {allItems.map((item, idx) => {
              const media = item.media;
              const alt   = media?.translated?.alt ?? media?.translated?.title
                         ?? media?.alt ?? media?.title ?? '';

              const itemStyle: CSSProperties = { width: `${100 / total}%`, flexShrink: 0 };

              const imgEl = media?.url ? (
                (isCover || isContain) ? (
                  <div className="relative w-full" style={{ height: fixedH }}>
                    <Image
                      src={media.url}
                      alt={alt}
                      fill
                      className={isCover ? 'object-cover' : 'object-contain'}
                      sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
                    />
                  </div>
                ) : (
                  <Image
                    src={media.url}
                    alt={alt}
                    width={media.width ?? 800}
                    height={media.height ?? 600}
                    className="w-full h-auto block"
                    style={hasMinH ? { minHeight: minHeightRaw, objectFit: 'cover' } : {}}
                    sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
                  />
                )
              ) : null;

              return (
                <div key={idx} style={itemStyle}>
                  {item.url ? (
                    <Link
                      href={item.url}
                      target={item.newTab ? '_blank' : undefined}
                      rel={item.newTab ? 'noopener noreferrer' : undefined}
                      className="block"
                    >
                      {imgEl}
                    </Link>
                  ) : imgEl}
                </div>
              );
            })}
          </div>
        </div>

        {/* ── Arrows (inside) ────────────────────────────────────────────── */}
        {showArrows && !arrowOut && (
          <>
            <button onClick={prev} disabled={atStart} aria-label="Previous" className={`${arrowInside} left-2`}>
              <ChevronLeft />
            </button>
            <button onClick={next} disabled={atEnd}   aria-label="Next"     className={`${arrowInside} right-2`}>
              <ChevronRight />
            </button>
          </>
        )}

        {/* ── Arrows (outside) ───────────────────────────────────────────── */}
        {showArrows && arrowOut && (
          <>
            <button onClick={prev} disabled={atStart} aria-label="Previous" className={`${arrowOutside} left-0`}>
              <ChevronLeft />
            </button>
            <button onClick={next} disabled={atEnd}   aria-label="Next"     className={`${arrowOutside} right-0`}>
              <ChevronRight />
            </button>
          </>
        )}
      </div>

      {/* ── Dots (inside — overlaid on slider bottom) ──────────────────────── */}
      {showDots && !dotOut && (
        <div className="absolute bottom-3 left-1/2 -translate-x-1/2 z-10 flex gap-1.5">
          {realItems.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>
      )}

      {/* ── Dots (outside — below slider) ─────────────────────────────────── */}
      {showDots && dotOut && (
        <div className="flex justify-center gap-1.5 mt-3">
          {realItems.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>
      )}
    </div>
  );
}
