import { useCallback, useEffect, useRef, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Heart, Loader2, Play, Shuffle, ThumbsDown, Sparkles, Square } from 'lucide-react';
import { vibeService, fetchNextBatch } from '../services/vibeService';
import { trackService } from '../services/trackService';
import { usePlaybackStore } from '../store/usePlaybackStore';
import { useVibeStore } from '../store/useVibeStore';
import { TrackRow } from '../components/TrackRow';
import { PageContainer } from '../components/PageContainer';
import type { Track } from '../types';
import { VibeTimeline } from '../components/VibeTimeline';
import { suppressAutoFeedback } from '../components/AudioEngine';
import { toast } from '../store/useToastStore';

const INITIAL_BATCH_SIZE = 5;
const PREFETCH_THRESHOLD = 3;
const PREFETCH_BATCH_SIZE = 3;

function bestEffort(p: Promise<unknown>): void {
  void p.catch(() => undefined);
}

export default function Vibe() {
  const { currentTrack, queue, setQueue, playTrack, next: playNext, pause, setCurrentTrack } = usePlaybackStore();
  const {
    activeSessionId,
    buffer,
    setActiveSession,
    setSeedTrackId,
    setCenterTrack,
    setBuffer,
    appendBuffer,
    reset,
  } = useVibeStore();

  const [starting, setStarting] = useState(false);
  const [prefetching, setPrefetching] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [empty, setEmpty] = useState(false);
  const prefetchingRef = useRef(false);

  const { data: libraryTracks = [], isLoading: libraryLoading } = useQuery<Track[]>({
    queryKey: ['library-seed'],
    queryFn: () => trackService.listTracks({ limit: 50, sort_by: 'play_count', order: 'DESC' }),
    enabled: !activeSessionId,
  });

  const startSession = useCallback(
    async (seed: Track) => {
      setStarting(true);
      setError(null);
      setEmpty(false);
      try {
        const { sessionId } = await vibeService.start(seed.id);
        setActiveSession({ sessionId, seedTrackId: seed.id });
        setSeedTrackId(seed.id);
        setCenterTrack(seed);

        const chunk = await fetchNextBatch(INITIAL_BATCH_SIZE);
        if (chunk.length === 0) {
          setBuffer([]);
          setEmpty(true);
          return;
        }
        setBuffer(chunk);
        setQueue(chunk);
        playTrack(chunk[0]);
      } catch {
        setError('Could not start a vibe session. Please try again.');
        reset();
      } finally {
        setStarting(false);
      }
    },
    [setActiveSession, setSeedTrackId, setCenterTrack, setBuffer, setQueue, playTrack, reset]
  );

  const startFromCurrent = useCallback(() => {
    if (currentTrack) void startSession(currentTrack);
  }, [currentTrack, startSession]);

  const surpriseMe = useCallback(() => {
    if (libraryTracks.length === 0) return;
    const seed = libraryTracks[Math.floor(Math.random() * libraryTracks.length)];
    void startSession(seed);
  }, [libraryTracks, startSession]);

  const remaining = currentTrack
    ? queue.length - (queue.findIndex((t) => t.id === currentTrack.id) + 1)
    : queue.length;

  useEffect(() => {
    if (!activeSessionId || prefetchingRef.current) return;
    if (remaining > PREFETCH_THRESHOLD) return;

    prefetchingRef.current = true;
    setPrefetching(true);
    fetchNextBatch(PREFETCH_BATCH_SIZE)
      .then((chunk) => {
        if (chunk.length > 0) {
          appendBuffer(chunk);
          const current = usePlaybackStore.getState().queue;
          const currentIds = new Set(current.map((t) => t.id));
          const fresh = chunk.filter((t) => !currentIds.has(t.id));
          if (fresh.length > 0) setQueue([...current, ...fresh]);
        }
      })
      .catch(() => undefined)
      .finally(() => {
        prefetchingRef.current = false;
        setPrefetching(false);
      });
  }, [activeSessionId, remaining, appendBuffer, setQueue]);

  // Trim buffer to prevent unbounded growth — keep only from currentTrack onward.
  useEffect(() => {
    if (!activeSessionId || !currentTrack || buffer.length === 0) return;
    const idx = buffer.findIndex((t) => t.id === currentTrack.id);
    if (idx > 0) {
      setBuffer(buffer.slice(idx));
    }
  }, [activeSessionId, currentTrack, buffer, setBuffer]);

  const handleKeep = useCallback(() => {
    if (currentTrack) {
      bestEffort(vibeService.feedback(currentTrack.id, 'promoted'));
      toast.success(`Kept "${currentTrack.title}"`);
    }
  }, [currentTrack]);

  const handleDislike = useCallback(() => {
    if (currentTrack) {
      bestEffort(vibeService.feedback(currentTrack.id, 'disliked'));
      // AudioEngine would otherwise also record a 'skipped' on the track
      // change caused by playNext() below — suppress that duplicate.
      suppressAutoFeedback(currentTrack.id);
    }
    playNext();
  }, [currentTrack, playNext]);

  const handleEnd = useCallback(() => {
    // V2 plan expires via Redis TTL (2h). No explicit end endpoint.
    pause();
    setQueue([]);
    setCurrentTrack(null);
    reset();
    setEmpty(false);
    setError(null);
  }, [reset, pause, setQueue, setCurrentTrack]);

  const upcoming = currentTrack
    ? (() => {
        const idx = buffer.findIndex((t) => t.id === currentTrack.id);
        return idx >= 0 ? buffer.slice(idx + 1) : buffer;
      })()
    : buffer;

  // ---- Start screen (no active session) ----
  if (!activeSessionId) {
    return (
      <PageContainer width="sm" className="py-8">
        <header className="space-y-2 text-center">
          <div className="inline-flex items-center gap-2 rounded-full bg-accent/10 px-4 py-1.5 text-sm text-accent">
            <Sparkles size={16} />
            Rolling Vibe
          </div>
          <h1 className="text-4xl font-bold text-text">Start a Vibe</h1>
          <p className="text-muted">
            An infinite, ever-rolling stream of recommendations seeded from a track you love.
          </p>
          <p className="mx-auto max-w-md text-xs text-muted/70">
            Pick a seed below and playback starts immediately, with a rolling
            timeline of upcoming tracks. <strong className="text-muted">Keep</strong> what you love,
            <strong className="text-muted"> Dislike &amp; skip</strong> what you don&apos;t — the vibe
            adapts as you go.
          </p>
        </header>

        {error && (
          <div className="rounded-lg border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-300">
            {error}
          </div>
        )}

        <div className="space-y-3">
          {currentTrack && (
            <button
              onClick={startFromCurrent}
              disabled={starting}
              className="flex w-full items-center gap-3 rounded-lg border border-accent/60 bg-accent/10 p-4 text-left transition-colors hover:bg-accent/20 disabled:opacity-60"
            >
              <Play size={20} className="text-accent" />
              <div className="flex-1">
                <div className="font-semibold text-text">Vibe from &ldquo;{currentTrack.title}&rdquo;</div>
                <div className="text-sm text-muted">{currentTrack.artist}</div>
              </div>
            </button>
          )}

          <button
            onClick={surpriseMe}
            disabled={starting || libraryLoading || libraryTracks.length === 0}
            className="flex w-full items-center gap-3 rounded-lg border border-border bg-surface0 p-4 text-left transition-colors hover:bg-surface1 disabled:opacity-60"
          >
            <Shuffle size={20} className="text-text" />
            <div className="flex-1">
              <div className="font-semibold text-text">Surprise me</div>
              <div className="text-sm text-muted">
                {libraryLoading
                  ? 'Loading your library…'
                  : libraryTracks.length === 0
                    ? 'No library tracks available to seed a vibe.'
                    : 'Start from a random track in your library.'}
              </div>
            </div>
            {starting && <Loader2 size={18} className="animate-spin text-muted" />}
          </button>
        </div>

        {!libraryLoading && libraryTracks.length > 0 && (
          <div className="space-y-2">
            <h2 className="text-sm font-semibold text-muted">Or pick a seed track</h2>
            <ul className="max-h-72 space-y-1 overflow-y-auto">
              {libraryTracks.map((track, index) => (
                <li key={track.id}>
                  <TrackRow
                    track={track}
                    queue={libraryTracks}
                    index={index}
                    showActions={false}
                  />
                </li>
              ))}
            </ul>
          </div>
        )}
      </PageContainer>
    );
  }

  // ---- Active session ----
  return (
    <PageContainer width="sm" className="py-6">
      <header className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <Sparkles size={22} className="text-accent" />
          <h1 className="text-2xl font-bold text-text">Vibing</h1>
          {prefetching && <Loader2 size={16} className="animate-spin text-muted" />}
        </div>
        <button
          onClick={handleEnd}
          className="flex items-center gap-2 rounded-lg border border-border px-3 py-1.5 text-sm text-text transition-colors hover:border-red-500/60 hover:text-red-300"
        >
          <Square size={14} />
          End Vibe
        </button>
      </header>

      {empty && (
        <div className="rounded-lg border border-border bg-surface0 p-4 text-sm text-muted">
          No recommendations came back for this seed yet. Try ending and starting a different vibe.
        </div>
      )}

      {currentTrack && (
        <div className="flex items-center gap-3">
          <button
            onClick={handleKeep}
            className="flex items-center gap-2 rounded-lg border border-border px-4 py-2 text-sm font-medium text-text transition-colors hover:border-pink-500/60 hover:text-pink-300"
          >
            <Heart size={16} />
            Keep
          </button>
          <button
            onClick={handleDislike}
            className="flex items-center gap-2 rounded-lg border border-border px-4 py-2 text-sm font-medium text-text transition-colors hover:border-red-500/60 hover:text-red-300"
          >
            <ThumbsDown size={16} />
            Dislike & skip
          </button>
        </div>
      )}

      <VibeTimeline currentTrack={currentTrack} upcoming={upcoming} />
    </PageContainer>
  );
}
