import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';
import { PlaylistList } from './PlaylistList';
import { usePlaylists } from '../hooks/usePlaylist';
import type { PlaylistListResponse } from '../types';

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

// Helper pour créer un QueryClient pour chaque test
function createWrapper() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        retry: false,
      },
      mutations: {
        retry: false,
      },
    },
  });

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

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

  it('should render loading state', () => {
    vi.mocked(usePlaylists).mockReturnValue({
      data: undefined,
      isLoading: true,
      error: null,
      isError: false,
      isSuccess: false,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList />, { wrapper: createWrapper() });

    expect(screen.getByText('Loading...')).toBeInTheDocument();
  });

  it('should render error state', () => {
    const error = new Error('Failed to load playlists');
    vi.mocked(usePlaylists).mockReturnValue({
      data: undefined,
      isLoading: false,
      error,
      isError: true,
      isSuccess: false,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList />, { wrapper: createWrapper() });

    expect(screen.getByText('Error loading playlists')).toBeInTheDocument();
    expect(screen.getByText('Failed to load playlists')).toBeInTheDocument();
  });

  it('should render empty state when no playlists', () => {
    vi.mocked(usePlaylists).mockReturnValue({
      data: { playlists: [], total: 0, page: 1, limit: 20 },
      isLoading: false,
      error: null,
      isError: false,
      isSuccess: true,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList />, { wrapper: createWrapper() });

    expect(screen.getByText('No playlists found')).toBeInTheDocument();
  });

  it('should render playlists in grid view by default', async () => {
    const mockResponse: PlaylistListResponse = {
      playlists: [
        {
          id: 1,
          user_id: 1,
          title: 'Playlist 1',
          is_public: true,
          track_count: 5,
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
        {
          id: 2,
          user_id: 1,
          title: 'Playlist 2',
          is_public: false,
          track_count: 10,
          created_at: '2024-01-02T00:00:00Z',
          updated_at: '2024-01-02T00:00:00Z',
        },
      ],
      total: 2,
      page: 1,
      limit: 20,
    };

    vi.mocked(usePlaylists).mockReturnValue({
      data: mockResponse,
      isLoading: false,
      error: null,
      isError: false,
      isSuccess: true,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList />, { wrapper: createWrapper() });

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

    // Check that grid view is active
    const gridButton = screen.getByLabelText('Grid view');
    expect(gridButton).toHaveAttribute('aria-pressed', 'true');
  });

  it('should toggle between grid and list view', async () => {
    const mockResponse: PlaylistListResponse = {
      playlists: [
        {
          id: 1,
          user_id: 1,
          title: 'Playlist 1',
          is_public: true,
          track_count: 5,
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ],
      total: 1,
      page: 1,
      limit: 20,
    };

    vi.mocked(usePlaylists).mockReturnValue({
      data: mockResponse,
      isLoading: false,
      error: null,
      isError: false,
      isSuccess: true,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList />, { wrapper: createWrapper() });

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

    const listButton = screen.getByLabelText('List view');
    listButton.click();

    await waitFor(() => {
      expect(listButton).toHaveAttribute('aria-pressed', 'true');
    });
  });

  it('should render pagination when there are multiple pages', async () => {
    const mockResponse: PlaylistListResponse = {
      playlists: [
        {
          id: 1,
          user_id: 1,
          title: 'Playlist 1',
          is_public: true,
          track_count: 5,
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ],
      total: 25,
      page: 1,
      limit: 20,
    };

    vi.mocked(usePlaylists).mockReturnValue({
      data: mockResponse,
      isLoading: false,
      error: null,
      isError: false,
      isSuccess: true,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList limit={20} />, { wrapper: createWrapper() });

    await waitFor(() => {
      expect(screen.getByText(/Page 1 of 2/)).toBeInTheDocument();
      expect(screen.getByText(/25 playlists/)).toBeInTheDocument();
    });

    expect(screen.getByText('Previous')).toBeInTheDocument();
    expect(screen.getByText('Next')).toBeInTheDocument();
  });

  it('should not render pagination when there is only one page', async () => {
    const mockResponse: PlaylistListResponse = {
      playlists: [
        {
          id: 1,
          user_id: 1,
          title: 'Playlist 1',
          is_public: true,
          track_count: 5,
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ],
      total: 1,
      page: 1,
      limit: 20,
    };

    vi.mocked(usePlaylists).mockReturnValue({
      data: mockResponse,
      isLoading: false,
      error: null,
      isError: false,
      isSuccess: true,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList />, { wrapper: createWrapper() });

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

    expect(screen.queryByText('Previous')).not.toBeInTheDocument();
    expect(screen.queryByText('Next')).not.toBeInTheDocument();
  });

  it('should use custom initial view', async () => {
    const mockResponse: PlaylistListResponse = {
      playlists: [
        {
          id: 1,
          user_id: 1,
          title: 'Playlist 1',
          is_public: true,
          track_count: 5,
          created_at: '2024-01-01T00:00:00Z',
          updated_at: '2024-01-01T00:00:00Z',
        },
      ],
      total: 1,
      page: 1,
      limit: 20,
    };

    vi.mocked(usePlaylists).mockReturnValue({
      data: mockResponse,
      isLoading: false,
      error: null,
      isError: false,
      isSuccess: true,
      refetch: vi.fn(),
    } as any);

    render(<PlaylistList view="list" />, { wrapper: createWrapper() });

    await waitFor(() => {
      const listButton = screen.getByLabelText('List view');
      expect(listButton).toHaveAttribute('aria-pressed', 'true');
    });
  });
});
