/**
 * Tests pour AddTrackToPlaylistModal
 * T0471: Create Add Track to Playlist Component
 */

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 { AddTrackToPlaylistModal } from './AddTrackToPlaylistModal';
import * as trackSearchService from '@/features/tracks/services/trackSearchService';
import * as playlistHooks from '../hooks/usePlaylist';
import type { Track } from '@/features/tracks/types/track';

// Mock des services
vi.mock('@/features/tracks/services/trackSearchService', () => ({
  searchTracks: vi.fn(),
}));

vi.mock('../hooks/usePlaylist', () => ({
  useAddTrackToPlaylist: vi.fn(),
}));

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>
  );
}

const mockTracks: Track[] = [
  {
    id: 1,
    user_id: 1,
    title: 'Track 1',
    artist: 'Artist 1',
    duration: 180,
    file_path: '/tracks/1.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: 2,
    user_id: 1,
    title: 'Track 2',
    artist: 'Artist 2',
    duration: 200,
    file_path: '/tracks/2.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',
  },
];

describe('AddTrackToPlaylistModal', () => {
  const mockMutateAsync = vi.fn();
  const mockToast = vi.fn();

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

    vi.mocked(playlistHooks.useAddTrackToPlaylist).mockReturnValue({
      mutateAsync: mockMutateAsync,
      isPending: false,
      isSuccess: false,
      isError: false,
      error: null,
      data: undefined,
      reset: vi.fn(),
      mutate: vi.fn(),
      status: 'idle',
    } as any);

    vi.mocked(trackSearchService.searchTracks).mockResolvedValue({
      tracks: mockTracks,
      pagination: {
        total: 2,
        page: 1,
        limit: 20,
        total_pages: 1,
      },
    });
  });

  it('should render modal when open', () => {
    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    expect(
      screen.getByText('Ajouter des tracks à la playlist'),
    ).toBeInTheDocument();
  });

  it('should not render modal when closed', () => {
    render(
      <AddTrackToPlaylistModal open={false} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    expect(
      screen.queryByText('Ajouter des tracks à la playlist'),
    ).not.toBeInTheDocument();
  });

  it('should display search input', () => {
    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    expect(
      screen.getByPlaceholderText('Rechercher des tracks...'),
    ).toBeInTheDocument();
  });

  it('should search tracks when query is entered', async () => {
    const user = userEvent.setup();
    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    const searchInput = screen.getByPlaceholderText('Rechercher des tracks...');
    await user.type(searchInput, 'test');

    await waitFor(
      () => {
        expect(trackSearchService.searchTracks).toHaveBeenCalled();
      },
      { timeout: 1000 },
    );
  });

  it('should display tracks after search', async () => {
    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    await waitFor(() => {
      expect(screen.getByText('Track 1')).toBeInTheDocument();
      expect(screen.getByText('Track 2')).toBeInTheDocument();
    });
  });

  it('should allow selecting tracks', async () => {
    const user = userEvent.setup();
    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    await waitFor(() => {
      expect(screen.getByText('Track 1')).toBeInTheDocument();
    });

    const checkboxes = screen.getAllByRole('checkbox');
    // Premier checkbox est "select all", deuxième est pour Track 1
    await user.click(checkboxes[1]);

    expect(checkboxes[1]).toBeChecked();
  });

  it('should allow selecting all tracks', async () => {
    const user = userEvent.setup();
    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    await waitFor(() => {
      expect(screen.getByText('Track 1')).toBeInTheDocument();
    });

    const checkboxes = screen.getAllByRole('checkbox');
    // Premier checkbox est "select all"
    await user.click(checkboxes[0]);

    // Tous les checkboxes doivent être cochés
    checkboxes.forEach((checkbox) => {
      expect(checkbox).toBeChecked();
    });
  });

  it('should add selected tracks to playlist', async () => {
    const user = userEvent.setup();
    mockMutateAsync.mockResolvedValue(undefined);

    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    await waitFor(() => {
      expect(screen.getByText('Track 1')).toBeInTheDocument();
    });

    const checkboxes = screen.getAllByRole('checkbox');
    await user.click(checkboxes[1]); // Sélectionner Track 1

    const addButton = screen.getByRole('button', { name: /ajouter/i });
    await user.click(addButton);

    await waitFor(() => {
      expect(mockMutateAsync).toHaveBeenCalledWith({
        playlistId: 1,
        trackId: 1,
      });
    });
  });

  it('should disable add button when no tracks selected', () => {
    render(
      <AddTrackToPlaylistModal open={true} onClose={vi.fn()} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    const addButton = screen.getByRole('button', { name: /ajouter/i });
    expect(addButton).toBeDisabled();
  });

  it('should close modal when cancel is clicked', async () => {
    const user = userEvent.setup();
    const onClose = vi.fn();

    render(
      <AddTrackToPlaylistModal open={true} onClose={onClose} playlistId={1} />,
      { wrapper: createWrapper() },
    );

    const cancelButton = screen.getByRole('button', { name: /annuler/i });
    await user.click(cancelButton);

    expect(onClose).toHaveBeenCalled();
  });
});
