import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { motion, type PanInfo } from 'framer-motion';

type PartnerSchool = { name: string; address: string | null };

interface Props {
  schools?: PartnerSchool[];
  visible?: number;
  autoplayMs?: number;
}

const VISIBLE_DEFAULT = 5;
const AUTOPLAY_MS = 5000;
const EASE: [number, number, number, number] = [0.22, 1, 0.36, 1];
const VELOCITY_THRESHOLD = 500;

export function SchoolCarousel({ schools = [], visible = VISIBLE_DEFAULT, autoplayMs = AUTOPLAY_MS }: Props) {
  const [idx, setIdx] = useState(0);
  const [paused, setPaused] = useState(false);
  const [dragging, setDragging] = useState(false);
  const [containerW, setContainerW] = useState(0);
  const containerRef = useRef<HTMLDivElement>(null);

  const n = schools.length;
  const itemW = containerW / visible;
  const maxIdx = Math.max(0, n - visible);
  const scrollable = n > visible;
  const totalDots = Math.max(1, Math.ceil(n / visible));
  const activeDot = Math.min(totalDots - 1, Math.round(idx / visible));

  // Measure container synchronously before paint, then track resizes.
  useLayoutEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    const measure = () => setContainerW(el.clientWidth);
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  // Keep index in range when data or viewport changes.
  useEffect(() => {
    setIdx((i) => Math.min(i, maxIdx));
  }, [maxIdx]);

  const goTo = useCallback(
    (i: number) => setIdx(Math.max(0, Math.min(i, maxIdx))),
    [maxIdx],
  );
  const next = useCallback(() => setIdx((i) => (i >= maxIdx ? 0 : i + 1)), [maxIdx]);
  const prev = useCallback(() => setIdx((i) => (i <= 0 ? maxIdx : i - 1)), [maxIdx]);

  // Autoplay (paused on hover or while dragging).
  useEffect(() => {
    if (paused || dragging || !scrollable) return;
    const t = window.setInterval(next, autoplayMs);
    return () => window.clearInterval(t);
  }, [paused, dragging, scrollable, next, autoplayMs]);

  // Keyboard navigation when the slider region is focused.
  const onKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (!scrollable) return;
      if (e.key === 'ArrowRight') {
        e.preventDefault();
        next();
      } else if (e.key === 'ArrowLeft') {
        e.preventDefault();
        prev();
      }
    },
    [scrollable, next, prev],
  );

  const handleDragEnd = useCallback(
    (_e: unknown, info: PanInfo) => {
      setDragging(false);
      if (!scrollable || itemW <= 0) return;
      // Velocity-aware snap: project the current offset forward, then round.
      const projectedOffset = info.offset.x + info.velocity.x * 0.2;
      const delta = Math.round(-projectedOffset / itemW);
      if (Math.abs(info.velocity.x) > VELOCITY_THRESHOLD && delta !== 0) {
        goTo(idx + Math.sign(delta) * Math.max(1, Math.abs(delta)));
      } else {
        goTo(idx + delta);
      }
    },
    [scrollable, itemW, idx, goTo],
  );

  const targetX = -idx * itemW;
  const constraints = { left: -maxIdx * itemW, right: 0 };

  return (
    <div className="lp-schools-panel">
      <div className="lp-schools-heading">
        <h2>مدارسی که با ما هستند</h2>
      </div>

      <div
        className="lp-school-slider"
        ref={containerRef}
        role="group"
        aria-roledescription="carousel"
        aria-label="مدارس همراه ما"
        tabIndex={scrollable ? 0 : -1}
        onKeyDown={onKeyDown}
        onMouseEnter={() => setPaused(true)}
        onMouseLeave={() => setPaused(false)}
      >
          {n === 0 ? (
            <div className="lp-school-strip is-skeleton">
              {Array.from({ length: visible }).map((_, i) => (
                <div key={i} className="lp-school-item">
                  <span className="lp-skel-line lp-skel-line--name" />
                  <span className="lp-skel-line lp-skel-line--addr" />
                </div>
              ))}
            </div>
          ) : (
            <motion.div
              className={`lp-school-strip${scrollable ? '' : ' is-centered'}`}
              style={{ width: '100%' }}
              animate={{ x: targetX }}
              transition={{ type: 'tween', duration: 0.6, ease: EASE }}
              drag={scrollable ? 'x' : false}
              dragConstraints={constraints}
              dragElastic={0.08}
              dragMomentum={false}
              onDragStart={() => setDragging(true)}
              onDragEnd={handleDragEnd}
            >
              {schools.map((school) => (
                <div
                  key={school.name}
                  className="lp-school-item"
                  style={{ flexBasis: `calc(100% / ${visible})` }}
                >
                  <strong>{school.name}</strong>
                  <small>{school.address}</small>
                </div>
              ))}
            </motion.div>
          )}
        </div>

      {totalDots > 1 && (
        <div className="lp-school-dots" aria-label="صفحه‌بندی مدارس">
          {Array.from({ length: totalDots }).map((_, i) => (
            <button
              type="button"
              key={i}
              className={i === activeDot ? 'active' : ''}
              aria-label={`صفحه ${i + 1}`}
              aria-current={i === activeDot ? 'true' : undefined}
              onClick={() => goTo(i * visible)}
            />
          ))}
        </div>
      )}
    </div>
  );
}
