import React from 'react';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { PlaylistSearch } from './PlaylistSearch';
import { searchPlaylists } from '../services/playlistService';
import type { Playlist } from '../types';

// Mock du service
jest.mock('../services/playlistService');
const mockSearchPlaylists = searchPlaylists as jest.MockedFunction<
  typeof searchPlaylists
>;

// Mock du hook useDebounce
jest.mock('@/hooks/useDebounce', () => ({
  useDebounce: (value: any) => value, // Retourne la valeur directement pour les tests
}));

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

// Mock de PlaylistCard
jest.mock('./PlaylistCard', () => ({
  PlaylistCard: ({
    playlist,
    onClick,
  }: {
    playlist: Playlist;
    onClick?: () => void;
  }) => (
    <div data-testid={`playlist-${playlist.id}`} onClick={onClick}>
      {playlist.title}
    </div>
  ),
}));

describe('PlaylistSearch', () => {
  const mockPlaylists: Playlist[] = [
    {
      id: 1,
      user_id: 1,
      title: 'Test Playlist 1',
      description: 'Description 1',
      is_public: true,
      cover_url: '',
      track_count: 5,
      followers_count: 10,
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-01T00:00:00Z',
    },
    {
      id: 2,
      user_id: 2,
      title: 'Test Playlist 2',
      description: 'Description 2',
      is_public: false,
      cover_url: '',
      track_count: 3,
      followers_count: 5,
      created_at: '2024-01-02T00:00:00Z',
      updated_at: '2024-01-02T00:00:00Z',
    },
  ];

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

  it('should render search input', () => {
    render(<PlaylistSearch />);
    expect(
      screen.getByPlaceholderText('Rechercher des playlists...'),
    ).toBeInTheDocument();
  });

  it('should display search results', async () => {
    mockSearchPlaylists.mockResolvedValue({
      playlists: mockPlaylists,
      total: 2,
      page: 1,
      limit: 20,
    });

    render(<PlaylistSearch />);

    const input = screen.getByPlaceholderText('Rechercher des playlists...');
    fireEvent.change(input, { target: { value: 'Test' } });

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

  it('should show loading state', async () => {
    mockSearchPlaylists.mockImplementation(
      () =>
        new Promise((resolve) =>
          setTimeout(
            () =>
              resolve({
                playlists: mockPlaylists,
                total: 2,
                page: 1,
                limit: 20,
              }),
            100,
          ),
        ),
    );

    render(<PlaylistSearch />);

    const input = screen.getByPlaceholderText('Rechercher des playlists...');
    fireEvent.change(input, { target: { value: 'Test' } });

    // Vérifier que le loader apparaît
    await waitFor(() => {
      expect(
        screen.getByRole('status') || document.querySelector('.animate-spin'),
      ).toBeInTheDocument();
    });
  });

  it('should toggle filters visibility', () => {
    render(<PlaylistSearch />);

    const filterButton = screen.getByRole('button', { name: /filter/i });
    fireEvent.click(filterButton);

    expect(screen.getByText('ID Utilisateur')).toBeInTheDocument();
    expect(screen.getByText('Statut')).toBeInTheDocument();
  });

  it('should apply filters', async () => {
    mockSearchPlaylists.mockResolvedValue({
      playlists: [mockPlaylists[0]],
      total: 1,
      page: 1,
      limit: 20,
    });

    render(<PlaylistSearch />);

    // Ouvrir les filtres
    const filterButton = screen.getByRole('button', { name: /filter/i });
    fireEvent.click(filterButton);

    // Appliquer le filtre is_public
    const statusSelect =
      screen.getByLabelText('Statut') || document.querySelector('select');
    if (statusSelect) {
      fireEvent.change(statusSelect, { target: { value: 'true' } });
    }

    await waitFor(() => {
      expect(mockSearchPlaylists).toHaveBeenCalledWith(
        expect.objectContaining({
          is_public: true,
        }),
      );
    });
  });

  it('should clear filters', async () => {
    mockSearchPlaylists.mockResolvedValue({
      playlists: [],
      total: 0,
      page: 1,
      limit: 20,
    });

    render(<PlaylistSearch />);

    const input = screen.getByPlaceholderText('Rechercher des playlists...');
    fireEvent.change(input, { target: { value: 'Test' } });

    await waitFor(() => {
      expect(mockSearchPlaylists).toHaveBeenCalled();
    });

    // Trouver le bouton clear (X)
    const clearButton = screen.getByRole('button', { name: /clear|reset|x/i });
    fireEvent.click(clearButton);

    await waitFor(() => {
      expect(input).toHaveValue('');
    });
  });

  it('should handle pagination', async () => {
    mockSearchPlaylists.mockResolvedValue({
      playlists: mockPlaylists,
      total: 25,
      page: 1,
      limit: 20,
    });

    render(<PlaylistSearch />);

    const input = screen.getByPlaceholderText('Rechercher des playlists...');
    fireEvent.change(input, { target: { value: 'Test' } });

    await waitFor(() => {
      expect(screen.getByText(/Page 1 sur/)).toBeInTheDocument();
    });

    // Cliquer sur suivant
    const nextButton = screen.getByRole('button', { name: /suivant/i });
    fireEvent.click(nextButton);

    await waitFor(() => {
      expect(mockSearchPlaylists).toHaveBeenCalledWith(
        expect.objectContaining({
          page: 2,
        }),
      );
    });
  });

  it('should call onPlaylistClick when playlist is clicked', async () => {
    const onPlaylistClick = jest.fn();
    mockSearchPlaylists.mockResolvedValue({
      playlists: [mockPlaylists[0]],
      total: 1,
      page: 1,
      limit: 20,
    });

    render(<PlaylistSearch onPlaylistClick={onPlaylistClick} />);

    const input = screen.getByPlaceholderText('Rechercher des playlists...');
    fireEvent.change(input, { target: { value: 'Test' } });

    await waitFor(() => {
      const playlistElement = screen.getByTestId('playlist-1');
      fireEvent.click(playlistElement);
      expect(onPlaylistClick).toHaveBeenCalledWith(mockPlaylists[0]);
    });
  });
});
