/**
 * Tests pour les hooks de gestion des tracks dans les playlists
 * T0470: Create PlaylistTrack Hooks
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import {
  useAddTrackToPlaylist,
  useRemoveTrackFromPlaylist,
  useReorderPlaylistTracks,
} from './usePlaylist';
import * as playlistService from '../services/playlistService';

// Mock du service
vi.mock('../services/playlistService', () => ({
  addTrackToPlaylist: vi.fn(),
  removeTrackFromPlaylist: vi.fn(),
  reorderPlaylistTracks: 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>
  );
}

describe('useAddTrackToPlaylist', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should add a track to playlist successfully', async () => {
    vi.mocked(playlistService.addTrackToPlaylist).mockResolvedValue(undefined);

    const { result } = renderHook(() => useAddTrackToPlaylist(), {
      wrapper: createWrapper(),
    });

    result.current.mutate({
      playlistId: 1,
      trackId: 10,
      position: 1,
    });

    await waitFor(() => expect(result.current.isSuccess).toBe(true));

    expect(playlistService.addTrackToPlaylist).toHaveBeenCalledWith(1, 10, 1);
  });

  it('should add a track without position', async () => {
    vi.mocked(playlistService.addTrackToPlaylist).mockResolvedValue(undefined);

    const { result } = renderHook(() => useAddTrackToPlaylist(), {
      wrapper: createWrapper(),
    });

    result.current.mutate({
      playlistId: 1,
      trackId: 10,
    });

    await waitFor(() => expect(result.current.isSuccess).toBe(true));

    expect(playlistService.addTrackToPlaylist).toHaveBeenCalledWith(
      1,
      10,
      undefined,
    );
  });

  it('should handle error when adding track fails', async () => {
    const error = new Error('Failed to add track');
    vi.mocked(playlistService.addTrackToPlaylist).mockRejectedValue(error);

    const { result } = renderHook(() => useAddTrackToPlaylist(), {
      wrapper: createWrapper(),
    });

    result.current.mutate({
      playlistId: 1,
      trackId: 10,
    });

    await waitFor(() => expect(result.current.isError).toBe(true));

    expect(result.current.error).toBe(error);
  });
});

describe('useRemoveTrackFromPlaylist', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should remove a track from playlist successfully', async () => {
    vi.mocked(playlistService.removeTrackFromPlaylist).mockResolvedValue(
      undefined,
    );

    const { result } = renderHook(() => useRemoveTrackFromPlaylist(), {
      wrapper: createWrapper(),
    });

    result.current.mutate({
      playlistId: 1,
      trackId: 10,
    });

    await waitFor(() => expect(result.current.isSuccess).toBe(true));

    expect(playlistService.removeTrackFromPlaylist).toHaveBeenCalledWith(1, 10);
  });

  it('should handle error when removing track fails', async () => {
    const error = new Error('Failed to remove track');
    vi.mocked(playlistService.removeTrackFromPlaylist).mockRejectedValue(error);

    const { result } = renderHook(() => useRemoveTrackFromPlaylist(), {
      wrapper: createWrapper(),
    });

    result.current.mutate({
      playlistId: 1,
      trackId: 10,
    });

    await waitFor(() => expect(result.current.isError).toBe(true));

    expect(result.current.error).toBe(error);
  });
});

describe('useReorderPlaylistTracks', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should reorder tracks successfully', async () => {
    vi.mocked(playlistService.reorderPlaylistTracks).mockResolvedValue(
      undefined,
    );

    const { result } = renderHook(() => useReorderPlaylistTracks(), {
      wrapper: createWrapper(),
    });

    const trackPositions = { 1: 1, 2: 2, 3: 3 };
    result.current.mutate({
      playlistId: 1,
      trackPositions,
    });

    await waitFor(() => expect(result.current.isSuccess).toBe(true));

    expect(playlistService.reorderPlaylistTracks).toHaveBeenCalledWith(
      1,
      trackPositions,
    );
  });

  it('should handle error when reordering tracks fails', async () => {
    const error = new Error('Failed to reorder tracks');
    vi.mocked(playlistService.reorderPlaylistTracks).mockRejectedValue(error);

    const { result } = renderHook(() => useReorderPlaylistTracks(), {
      wrapper: createWrapper(),
    });

    result.current.mutate({
      playlistId: 1,
      trackPositions: { 1: 1 },
    });

    await waitFor(() => expect(result.current.isError).toBe(true));

    expect(result.current.error).toBe(error);
  });
});
