/**
 * Composant pour afficher la liste des tracks d'une playlist
 * T0473: Create Playlist Track List Component
 * T0474: Create Drag and Drop for Playlist Tracks
 */

import { useState, useEffect } from 'react';
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  DragEndEvent,
} from '@dnd-kit/core';
import {
  arrayMove,
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { cn } from '@/lib/utils';
import { PlaylistTrackItem } from './PlaylistTrackItem';
import type { PlaylistTrack, Track } from '../types';
import { Music } from 'lucide-react';
import { useReorderPlaylistTracks } from '../hooks/usePlaylist';
import { useToast } from '@/hooks/useToast';

interface PlaylistTrackListProps {
  playlistTracks: PlaylistTrack[];
  tracks: Track[];
  playlistId: string;
  onTrackClick?: (track: Track) => void;
  onTrackPlay?: (track: Track) => void;
  onTrackRemoved?: () => void;
  onTracksReordered?: () => void;
  isPlaying?: (trackId: string) => boolean;
  currentPlayingId?: string;
  className?: string;
  emptyMessage?: string;
  emptyDescription?: string;
  enableDragAndDrop?: boolean;
  canRemoveTracks?: boolean;
}

/**
 * Trie les tracks par position dans la playlist
 */
function sortTracksByPosition(
  playlistTracks: PlaylistTrack[],
): PlaylistTrack[] {
  return [...playlistTracks].sort((a, b) => a.position - b.position);
}

/**
 * Composant wrapper pour un item draggable
 */
function SortablePlaylistTrackItem({
  playlistTrack,
  track,
  playlistId,
  position,
  onTrackClick,
  onTrackPlay,
  onTrackRemoved,
  isPlaying,
  canRemoveTracks,
}: {
  playlistTrack: PlaylistTrack;
  track: Track;
  playlistId: string;
  position: number;
  onTrackClick?: (track: Track) => void;
  onTrackPlay?: (track: Track) => void;
  onTrackRemoved?: () => void;
  isPlaying: boolean;
  canRemoveTracks?: boolean;
}) {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id: playlistTrack.id });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1,
  };

  return (
    <div ref={setNodeRef} style={style}>
      <PlaylistTrackItem
        playlistTrack={playlistTrack}
        track={track}
        playlistId={playlistId}
        position={position}
        onTrackClick={onTrackClick}
        onTrackPlay={onTrackPlay}
        onTrackRemoved={onTrackRemoved}
        isPlaying={isPlaying}
        dragHandleProps={{ ...attributes, ...listeners }}
        canRemoveTracks={canRemoveTracks}
      />
    </div>
  );
}

export function PlaylistTrackList({
  playlistTracks,
  tracks,
  playlistId,
  onTrackClick,
  onTrackPlay,
  onTrackRemoved,
  onTracksReordered,
  isPlaying,
  currentPlayingId,
  className,
  emptyMessage = 'Aucun track dans cette playlist',
  emptyDescription = 'Ajoutez des tracks à cette playlist pour commencer.',
  enableDragAndDrop = true,
  canRemoveTracks = true,
}: PlaylistTrackListProps) {
  // Trier les tracks par position
  const [sortedPlaylistTracks, setSortedPlaylistTracks] = useState(() =>
    sortTracksByPosition(playlistTracks),
  );

  // Mettre à jour l'état local quand les props changent
  useEffect(() => {
    setSortedPlaylistTracks(sortTracksByPosition(playlistTracks));
  }, [playlistTracks]);

  // Créer une map pour un accès rapide aux tracks
  const trackMap = new Map<string, Track>(
    tracks.map((track) => [track.id, track]),
  );

  const { toast, error } = useToast();
  const reorderMutation = useReorderPlaylistTracks();

  // Configurer les sensors pour le drag-and-drop
  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 8, // Délai de 8px avant d'activer le drag
      },
    }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  );

  // Vérifier si un track est en cours de lecture
  const checkIsPlaying = (trackId: string): boolean => {
    if (currentPlayingId === trackId) return true;
    return isPlaying?.(trackId) ?? false;
  };

  // Gérer la fin du drag
  const handleDragEnd = async (event: DragEndEvent) => {
    const { active, over } = event;

    if (!over || active.id === over.id) {
      return;
    }

    const oldIndex = sortedPlaylistTracks.findIndex(
      (pt) => pt.id === active.id,
    );
    const newIndex = sortedPlaylistTracks.findIndex((pt) => pt.id === over.id);

    if (oldIndex === -1 || newIndex === -1) {
      return;
    }

    // Mettre à jour l'ordre localement (optimistic update)
    const newOrder = arrayMove(sortedPlaylistTracks, oldIndex, newIndex);
    setSortedPlaylistTracks(newOrder);

    // Liste des IDs dans le nouvel ordre
    const trackIds = newOrder.map((pt) => pt.track_id);

    try {
      // Appeler l'API pour mettre à jour les positions
      await reorderMutation.mutateAsync({
        playlistId: String(playlistId),
        trackIds,
      });

      toast({
        message: 'Playlist réorganisée',
        type: 'success',
      });

      onTracksReordered?.();
    } catch (err) {
      // En cas d'erreur, restaurer l'ordre précédent
      setSortedPlaylistTracks(sortTracksByPosition(playlistTracks));

      error('Impossible de réorganiser la playlist. Veuillez réessayer.');
    }
  };

  // État vide
  if (sortedPlaylistTracks.length === 0) {
    return (
      <div
        className={cn(
          'flex flex-col items-center justify-center py-12 text-center',
          className,
        )}
      >
        <Music className="h-12 w-12 text-muted-foreground mb-4 opacity-50" />
        <p className="text-lg font-medium text-gray-900 dark:text-white mb-2">
          {emptyMessage}
        </p>
        {emptyDescription && (
          <p className="text-sm text-muted-foreground max-w-md">
            {emptyDescription}
          </p>
        )}
      </div>
    );
  }

  const trackIds = sortedPlaylistTracks.map((pt) => pt.id);

  // Si drag-and-drop est désactivé, afficher la liste normale
  if (!enableDragAndDrop) {
    return (
      <div
        className={cn('space-y-1', className)}
        role="list"
        aria-label="Liste des tracks de la playlist"
      >
        {sortedPlaylistTracks.map((playlistTrack) => {
          const track = trackMap.get(playlistTrack.track_id);

          if (!track) {
            return null;
          }

          return (
            <PlaylistTrackItem
              key={playlistTrack.id}
              playlistTrack={playlistTrack}
              track={track}
              playlistId={playlistId}
              position={playlistTrack.position}
              onTrackClick={onTrackClick}
              onTrackPlay={onTrackPlay}
              onTrackRemoved={onTrackRemoved}
              isPlaying={checkIsPlaying(track.id)}
              canRemoveTracks={canRemoveTracks}
            />
          );
        })}
      </div>
    );
  }

  // Liste avec drag-and-drop
  return (
    <DndContext
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragEnd={handleDragEnd}
    >
      <SortableContext items={trackIds} strategy={verticalListSortingStrategy}>
        <div
          className={cn('space-y-1', className)}
          role="list"
          aria-label="Liste des tracks de la playlist"
        >
          {sortedPlaylistTracks.map((playlistTrack) => {
            const track = trackMap.get(playlistTrack.track_id);

            if (!track) {
              return null;
            }

            return (
              <SortablePlaylistTrackItem
                key={playlistTrack.id}
                playlistTrack={playlistTrack}
                track={track}
                playlistId={playlistId}
                position={playlistTrack.position}
                onTrackClick={onTrackClick}
                onTrackPlay={onTrackPlay}
                onTrackRemoved={onTrackRemoved}
                isPlaying={checkIsPlaying(track.id)}
                canRemoveTracks={canRemoveTracks}
              />
            );
          })}
        </div>
      </SortableContext>
    </DndContext>
  );
}
