import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import React, { useRef, useState, useEffect, useMemo } from 'react';
import { ChevronLeft, ChevronRight, RefreshCw } from 'lucide-react';
import SongCard from '@/features/home/components/SongCard';
import { usePerfProbeFlags } from '@/utils/perf/perfFlags';
import { dedupeById } from '@/lib/util/dedupeById';

interface Props {
  title: string;
  songs: SubsonicSong[];
  /** Called when user clicks the reroll button (visible only if provided). */
  onReroll?: () => void | Promise<void>;
  /** Loading state — disables reroll, optional shimmer */
  loading?: boolean;
  /** Empty-state copy when songs is empty AND not loading. */
  emptyText?: string;
  disableArtwork?: boolean;
  disableInteractivity?: boolean;
  artworkSize?: number;
  windowArtworkByViewport?: boolean;
  initialArtworkBudget?: number;
}

export default function SongRail({
  title,
  songs,
  onReroll,
  loading,
  emptyText,
  disableArtwork = false,
  disableInteractivity = false,
  artworkSize,
  windowArtworkByViewport = false,
  initialArtworkBudget = 10,
}: Props) {
  const perfFlags = usePerfProbeFlags();
  const artworkDisabled = perfFlags.disableMainstageRailArtwork || disableArtwork;
  const interactivityDisabled = perfFlags.disableMainstageRailInteractivity || disableInteractivity;
  const scrollRef = useRef<HTMLDivElement>(null);
  const uniqueSongs = useMemo(() => dedupeById(songs), [songs]);
  const [showLeft, setShowLeft] = useState(false);
  const [showRight, setShowRight] = useState(true);
  const [artworkBudget, setArtworkBudget] = useState(initialArtworkBudget);

  const recomputeArtworkBudget = () => {
    if (!windowArtworkByViewport) return;
    const el = scrollRef.current;
    if (!el) return;
    const { scrollLeft, clientWidth } = el;
    const firstCard = el.querySelector<HTMLElement>('.song-card');
    const cardW = firstCard?.clientWidth || firstCard?.getBoundingClientRect().width || 140;
    const gridStyles = window.getComputedStyle(el);
    const gap = Number.parseFloat(gridStyles.columnGap || gridStyles.gap || '12') || 12;
    const step = Math.max(1, cardW + gap);
    const visibleCount = Math.ceil((scrollLeft + clientWidth) / step);
    const nextBudget = Math.max(initialArtworkBudget, visibleCount + 12);
    setArtworkBudget(prev => (nextBudget > prev ? nextBudget : prev));
  };

  const handleScroll = () => {
    if (windowArtworkByViewport) recomputeArtworkBudget();

    if (!scrollRef.current) return;
    const { scrollLeft, scrollWidth, clientWidth } = scrollRef.current;

    if (!interactivityDisabled) {
      setShowLeft(scrollLeft > 0);
      setShowRight(scrollLeft < scrollWidth - clientWidth - 5);
    }
  };

  useEffect(() => {
    handleScroll();
    const raf = window.requestAnimationFrame(() => {
      if (windowArtworkByViewport) recomputeArtworkBudget();
    });
    window.addEventListener('resize', handleScroll);
    const ro = new ResizeObserver(() => {
      if (windowArtworkByViewport) recomputeArtworkBudget();
    });
    if (scrollRef.current) ro.observe(scrollRef.current);
    return () => {
      window.cancelAnimationFrame(raf);
      window.removeEventListener('resize', handleScroll);
      ro.disconnect();
    };
    // handleScroll/recomputeArtworkBudget are recreated each render but read live
    // refs/props; the listeners are intentionally (re)bound only when the row data
    // or artwork config changes, not on every render.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [uniqueSongs, interactivityDisabled, windowArtworkByViewport, initialArtworkBudget]);

  const rowArtworkResetKey = uniqueSongs[0]?.id ?? '';
  useEffect(() => {
    // React Compiler set-state-in-effect rule: state set from a DOM/layout measurement.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setArtworkBudget(initialArtworkBudget);
  }, [initialArtworkBudget, rowArtworkResetKey]);

  const scroll = (dir: 'left' | 'right') => {
    if (!scrollRef.current) return;
    const amount = scrollRef.current.clientWidth * 0.75;
    scrollRef.current.scrollBy({ left: dir === 'left' ? -amount : amount, behavior: 'smooth' });
  };

  // Hide rail entirely if empty and no empty-state copy
  if (uniqueSongs.length === 0 && !loading && !emptyText) return null;

  return (
    <section className="song-row-section">
      <div className="song-row-header">
        <h2 className="section-title" style={{ marginBottom: 0 }}>{title}</h2>
        <div className="song-row-nav">
          {onReroll && (
            <button
              className="nav-btn song-row-reroll"
              onClick={() => onReroll()}
              disabled={loading}
              aria-label="Reroll"
              data-tooltip="Reroll"
              data-tooltip-pos="top"
            >
              <RefreshCw size={16} className={loading ? 'is-spinning' : ''} />
            </button>
          )}
          {!interactivityDisabled && (
            <>
              <button
                className={`nav-btn ${!showLeft ? 'disabled' : ''}`}
                onClick={() => scroll('left')}
                disabled={!showLeft}
              >
                <ChevronLeft size={20} />
              </button>
              <button
                className={`nav-btn ${!showRight ? 'disabled' : ''}`}
                onClick={() => scroll('right')}
                disabled={!showRight}
              >
                <ChevronRight size={20} />
              </button>
            </>
          )}
        </div>
      </div>

      <div className="song-grid-wrapper">
        {uniqueSongs.length === 0 && emptyText ? (
          <p className="song-row-empty">{emptyText}</p>
        ) : (
          <div className="song-grid" ref={scrollRef} onScroll={handleScroll}>
            {uniqueSongs.map((s, idx) => (
              <SongCard
                key={s.id}
                song={s}
                disableArtwork={
                  artworkDisabled ||
                  (windowArtworkByViewport && idx >= artworkBudget)
                }
                artworkSize={artworkSize}
              />
            ))}
          </div>
        )}
      </div>
    </section>
  );
}
