/**
 * Tests pour PlaylistTrackList
 * T0473: Create Playlist Track List Component
 * T0474: Create Drag and Drop for Playlist Tracks
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { PlaylistTrackList } from './PlaylistTrackList';
import type { PlaylistTrack } from '../types';
import type { Track } from '@/features/tracks/types/track';

const mockMutateAsync = vi.fn();

// Mock useReorderPlaylistTracks
vi.mock('../hooks/usePlaylist', async () => {
  const actual = await vi.importActual('../hooks/usePlaylist');
  return {
    ...actual,
    useReorderPlaylistTracks: vi.fn(() => ({
      mutateAsync: mockMutateAsync,
      isPending: false,
      isSuccess: false,
      isError: false,
      error: null,
      data: undefined,
      reset: vi.fn(),
      mutate: vi.fn(),
      status: 'idle',
    })),
  };
});

// Mock useToast
vi.mock('@/hooks/useToast', () => ({
  useToast: () => ({
    toast: vi.fn(),
  }),
}));

function createWrapper() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
}

// Mock PlaylistTrackItem
vi.mock('./PlaylistTrackItem', () => ({
  PlaylistTrackItem: ({ track, position }: any) => (
    <div data-testid="playlist-track-item">
      {position}. {track.title}
    </div>
  ),
}));

const mockPlaylistTracks: PlaylistTrack[] = [
  {
    id: 1,
    playlist_id: 1,
    track_id: 10,
    position: 1,
    added_at: '2024-01-01T00:00:00Z',
  },
  {
    id: 2,
    playlist_id: 1,
    track_id: 20,
    position: 2,
    added_at: '2024-01-01T00:00:00Z',
  },
  {
    id: 3,
    playlist_id: 1,
    track_id: 30,
    position: 3,
    added_at: '2024-01-01T00:00:00Z',
  },
];

const mockTracks: Track[] = [
  {
    id: 10,
    user_id: 1,
    title: 'Track 1',
    artist: 'Artist 1',
    duration: 180,
    file_path: '/tracks/10.mp3',
    file_size: 5000000,
    format: 'MP3',
    is_public: true,
    play_count: 0,
    like_count: 0,
    created_at: '2024-01-01T00:00:00Z',
    updated_at: '2024-01-01T00:00:00Z',
  },
  {
    id: 20,
    user_id: 1,
    title: 'Track 2',
    artist: 'Artist 2',
    duration: 200,
    file_path: '/tracks/20.mp3',
    file_size: 6000000,
    format: 'MP3',
    is_public: true,
    play_count: 0,
    like_count: 0,
    created_at: '2024-01-01T00:00:00Z',
    updated_at: '2024-01-01T00:00:00Z',
  },
  {
    id: 30,
    user_id: 1,
    title: 'Track 3',
    artist: 'Artist 3',
    duration: 220,
    file_path: '/tracks/30.mp3',
    file_size: 7000000,
    format: 'MP3',
    is_public: true,
    play_count: 0,
    like_count: 0,
    created_at: '2024-01-01T00:00:00Z',
    updated_at: '2024-01-01T00:00:00Z',
  },
];

describe('PlaylistTrackList', () => {
  const mockOnTrackClick = vi.fn();
  const mockOnTrackPlay = vi.fn();
  const mockOnTrackRemoved = vi.fn();
  const mockOnTracksReordered = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should render empty state when no tracks', () => {
    render(
      <PlaylistTrackList playlistTracks={[]} tracks={[]} playlistId={1} />,
    );

    expect(
      screen.getByText('Aucun track dans cette playlist'),
    ).toBeInTheDocument();
  });

  it('should render custom empty message', () => {
    render(
      <PlaylistTrackList
        playlistTracks={[]}
        tracks={[]}
        playlistId={1}
        emptyMessage="Custom empty message"
      />,
      { wrapper: createWrapper() },
    );

    expect(screen.getByText('Custom empty message')).toBeInTheDocument();
  });

  it('should render tracks in order', () => {
    render(
      <PlaylistTrackList
        playlistTracks={mockPlaylistTracks}
        tracks={mockTracks}
        playlistId={1}
      />,
      { wrapper: createWrapper() },
    );

    const items = screen.getAllByTestId('playlist-track-item');
    expect(items).toHaveLength(3);
    expect(items[0]).toHaveTextContent('1. Track 1');
    expect(items[1]).toHaveTextContent('2. Track 2');
    expect(items[2]).toHaveTextContent('3. Track 3');
  });

  it('should sort tracks by position even if unsorted', () => {
    const unsortedPlaylistTracks: PlaylistTrack[] = [
      {
        id: 3,
        playlist_id: 1,
        track_id: 30,
        position: 3,
        added_at: '2024-01-01T00:00:00Z',
      },
      {
        id: 1,
        playlist_id: 1,
        track_id: 10,
        position: 1,
        added_at: '2024-01-01T00:00:00Z',
      },
      {
        id: 2,
        playlist_id: 1,
        track_id: 20,
        position: 2,
        added_at: '2024-01-01T00:00:00Z',
      },
    ];

    render(
      <PlaylistTrackList
        playlistTracks={unsortedPlaylistTracks}
        tracks={mockTracks}
        playlistId={1}
      />,
      { wrapper: createWrapper() },
    );

    const items = screen.getAllByTestId('playlist-track-item');
    expect(items[0]).toHaveTextContent('1. Track 1');
    expect(items[1]).toHaveTextContent('2. Track 2');
    expect(items[2]).toHaveTextContent('3. Track 3');
  });

  it('should not render tracks that are not found', () => {
    const playlistTracksWithMissing: PlaylistTrack[] = [
      ...mockPlaylistTracks,
      {
        id: 4,
        playlist_id: 1,
        track_id: 999, // Track qui n'existe pas
        position: 4,
        added_at: '2024-01-01T00:00:00Z',
      },
    ];

    render(
      <PlaylistTrackList
        playlistTracks={playlistTracksWithMissing}
        tracks={mockTracks}
        playlistId={1}
      />,
      { wrapper: createWrapper() },
    );

    const items = screen.getAllByTestId('playlist-track-item');
    expect(items).toHaveLength(3); // Seulement les 3 tracks existants
  });

  it('should pass callbacks to items', () => {
    render(
      <PlaylistTrackList
        playlistTracks={mockPlaylistTracks}
        tracks={mockTracks}
        playlistId={1}
        onTrackClick={mockOnTrackClick}
        onTrackPlay={mockOnTrackPlay}
        onTrackRemoved={mockOnTrackRemoved}
      />,
      { wrapper: createWrapper() },
    );

    // Les callbacks sont passés via les props, on vérifie juste que le composant se rend
    const items = screen.getAllByTestId('playlist-track-item');
    expect(items).toHaveLength(3);
  });

  it('should check if track is playing', () => {
    const mockIsPlaying = vi.fn((trackId: number) => trackId === 20);

    render(
      <PlaylistTrackList
        playlistTracks={mockPlaylistTracks}
        tracks={mockTracks}
        playlistId={1}
        isPlaying={mockIsPlaying}
      />,
      { wrapper: createWrapper() },
    );

    // Le composant devrait vérifier si les tracks sont en cours de lecture
    const items = screen.getAllByTestId('playlist-track-item');
    expect(items).toHaveLength(3);
  });

  it('should check currentPlayingId', () => {
    render(
      <PlaylistTrackList
        playlistTracks={mockPlaylistTracks}
        tracks={mockTracks}
        playlistId={1}
        currentPlayingId={20}
      />,
      { wrapper: createWrapper() },
    );

    const items = screen.getAllByTestId('playlist-track-item');
    expect(items).toHaveLength(3);
  });

  it('should disable drag and drop when enableDragAndDrop is false', () => {
    render(
      <PlaylistTrackList
        playlistTracks={mockPlaylistTracks}
        tracks={mockTracks}
        playlistId={1}
        enableDragAndDrop={false}
      />,
      { wrapper: createWrapper() },
    );

    const items = screen.getAllByTestId('playlist-track-item');
    expect(items).toHaveLength(3);
    // Le handle de drag ne devrait pas être présent
  });

  it('should call onTracksReordered when tracks are reordered', async () => {
    mockMutateAsync.mockResolvedValue(undefined);

    render(
      <PlaylistTrackList
        playlistTracks={mockPlaylistTracks}
        tracks={mockTracks}
        playlistId={1}
        onTracksReordered={mockOnTracksReordered}
        enableDragAndDrop={true}
      />,
      { wrapper: createWrapper() },
    );

    // Le drag-and-drop nécessite une interaction utilisateur réelle
    // On vérifie juste que le composant se rend correctement
    const items = screen.getAllByTestId('playlist-track-item');
    expect(items).toHaveLength(3);
  });
});
