import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Icon from '../../shared/components/icon';

export interface SliderProps {
  path?: string;
  images: string[];
  mode?: 'auto' | 'manual';
  intervalMs?: number;
  className?: string;
}

const DRAG_FRICTION = 0.9;

const buildSrc = (path: string | undefined, img: string) => {
  if (/^(https?:)?\/\//i.test(img) || img.startsWith('data:') || img.startsWith('blob:')) {
    return img;
  }

  if (!path) return img;

  const p = path.endsWith('/') ? path.slice(0, -1) : path;
  const i = img.startsWith('/') ? img.slice(1) : img;

  return `${p}/${i}`;
};

const Slider: React.FC<SliderProps> = ({ path, images, mode = 'manual', intervalMs = 3500, className = '' }) => {
  const count = images.length;
  if (count === 0) return null;

  const renderedSlides = useMemo(() => {
    if (count <= 1) return images;
    return [images[count - 1], ...images, images[0]];
  }, [images, count]);

  const [trackIndex, setTrackIndex] = useState(count > 1 ? 1 : 0);
  const [isAnimating, setIsAnimating] = useState(true);

  const [dragX, setDragX] = useState(0);
  const [isDragging, setIsDragging] = useState(false);

  const timerRef = useRef<number | null>(null);
  const pointerStartX = useRef(0);
  const pointerIdRef = useRef<number | null>(null);

  const viewportRef = useRef<HTMLDivElement | null>(null);
  const [viewportWidth, setViewportWidth] = useState(0);

  const transitionLockRef = useRef(false);

  useEffect(() => {
    const el = viewportRef.current;
    if (!el) return;

    const update = () => setViewportWidth(el.clientWidth);

    update();

    const ro = new ResizeObserver(() => update());
    ro.observe(el);

    return () => ro.disconnect();
  }, []);

  const sliderClass = useMemo(() => ['slider', mode === 'auto' ? 'slider--auto' : 'slider--manual', className].filter(Boolean).join(' '), [mode, className]);

  const goNext = useCallback(() => {
    if (count <= 1) return;
    if (transitionLockRef.current) return;
    transitionLockRef.current = true;
    setIsAnimating(true);
    setTrackIndex((i) => i + 1);
  }, [count]);

  const goPrev = useCallback(() => {
    if (count <= 1) return;
    if (transitionLockRef.current) return;
    transitionLockRef.current = true;
    setIsAnimating(true);
    setTrackIndex((i) => i - 1);
  }, [count]);

  useEffect(() => {
    if (mode !== 'auto' || count <= 1) return;

    if (!isDragging) {
      timerRef.current = window.setInterval(goNext, intervalMs);
    }

    return () => {
      if (timerRef.current) {
        window.clearInterval(timerRef.current);
        timerRef.current = null;
      }
    };
  }, [mode, intervalMs, count, isDragging, goNext]);

  const onTransitionEnd = useCallback(() => {
    if (count <= 1) return;
    transitionLockRef.current = false;

    if (trackIndex === renderedSlides.length - 1) {
      setIsAnimating(false);
      setTrackIndex(1);
    } else if (trackIndex === 0) {
      setIsAnimating(false);
      setTrackIndex(renderedSlides.length - 2);
    }
  }, [count, trackIndex, renderedSlides.length]);

  useEffect(() => {
    if (isAnimating) return;
    const id = window.setTimeout(() => setIsAnimating(true), 0);
    return () => window.clearTimeout(id);
  }, [isAnimating]);

  const activeDot = useMemo(() => {
    if (count <= 1) return 0;

    let real = trackIndex - 1;
    if (trackIndex === 0) real = count - 1;
    if (trackIndex === renderedSlides.length - 1) real = 0;

    return real;
  }, [trackIndex, count, renderedSlides.length]);

  const goToRealIndex = useCallback(
    (realIndex: number) => {
      if (count <= 1) return;
      if (transitionLockRef.current) return;
      transitionLockRef.current = true;
      setIsAnimating(true);
      setTrackIndex(realIndex + 1);
    },
    [count]
  );

  const onPointerDown = (e: React.PointerEvent) => {
    if (count <= 1) return;
    pointerIdRef.current = e.pointerId;
    pointerStartX.current = e.clientX;
    setIsDragging(true);
    setDragX(0);
    (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
  };

  const onPointerMove = (e: React.PointerEvent) => {
    if (!isDragging) return;
    if (pointerIdRef.current !== e.pointerId) return;

    const delta = (e.clientX - pointerStartX.current) * DRAG_FRICTION;
    setDragX(delta);
  };

  const endDrag = (e: React.PointerEvent) => {
    if (!isDragging) return;
    if (pointerIdRef.current !== e.pointerId) return;

    try {
      (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId);
    } catch {}

    const delta = dragX;

    setIsDragging(false);
    setDragX(0);
    pointerIdRef.current = null;

    const threshold = viewportWidth > 0 ? viewportWidth * 0.12 : 60;

    if (Math.abs(delta) >= threshold) {
      if (delta < 0) goNext();
      else goPrev();
    }
  };

  const x = -(trackIndex * viewportWidth) + (isDragging ? dragX : 0);

  const trackStyle: React.CSSProperties = {
    transform: `translate3d(${x}px, 0, 0)`,
    transition: isDragging || !isAnimating ? 'none' : undefined
  };

  return (
    <section className={sliderClass} aria-roledescription="carousel" aria-label="Image slider">
      <div className="slider__container">
        <div
          className="slider__viewport"
          ref={viewportRef}
          onPointerDown={onPointerDown}
          onPointerMove={onPointerMove}
          onPointerUp={endDrag}
          onPointerCancel={endDrag}
          role="group"
          aria-label="Slides">
          <div className="slider__track" style={trackStyle as any} onTransitionEnd={onTransitionEnd}>
            {renderedSlides.map((img, i) => {
              const realIndex = count <= 1 ? 0 : i === 0 ? count - 1 : i === renderedSlides.length - 1 ? 0 : i - 1;

              return (
                <div className="slider__slide" key={`${img}-${i}`}>
                  <img className="slider__img" src={buildSrc(path, img)} alt={`Slide ${realIndex + 1} of ${count}`} draggable={false} />
                </div>
              );
            })}
          </div>
        </div>

        {mode === 'manual' && count > 1 && (
          <div className="slider__controls">
            <button type="button" className="slider__btn slider__btn--prev" onClick={goPrev} aria-label="Previous slide">
              <Icon name="ui-chevron" width={24} height={24} />
            </button>

            <div className="slider__dots">
              {images.map((_, i) => (
                <button
                  key={i}
                  className={`slider__dot ${i === activeDot ? 'is-active' : ''}`}
                  onClick={() => goToRealIndex(i)}
                  aria-label={`Go to slide ${i + 1}`}
                  aria-current={i === activeDot ? 'true' : undefined}
                />
              ))}
            </div>

            <button type="button" className="slider__btn slider__btn--next" onClick={goNext} aria-label="Next slide">
              <Icon name="ui-chevron" width={24} height={24} />
            </button>
          </div>
        )}
      </div>
    </section>
  );
};

export default Slider;
