import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import userEvent from '@testing-library/user-event';
import { TrackSearch } from './TrackSearch';
import { searchTracks, TrackSearchError } from '../services/trackSearchService';
import type { Track } from '../types/track';

// Mock dependencies
vi.mock('../services/trackSearchService');
vi.mock('@/hooks/useDebounce', () => ({
  useDebounce: (value: any) => value, // Return value immediately for testing
}));

describe('TrackSearch', () => {
  const mockTracks: Track[] = [
    {
      id: 1,
      creator_id: 123,
      title: 'Test Track',
      artist: 'Test Artist',
      duration: 180,
      file_path: '/test/track.mp3',
      file_size: 5000000,
      format: 'MP3',
      is_public: true,
      play_count: 10,
      like_count: 5,
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-01T00:00:00Z',
    },
  ];

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

  it('should render search input and button', () => {
    vi.mocked(searchTracks).mockResolvedValue({
      tracks: [],
      pagination: {
        page: 1,
        limit: 20,
        total: 0,
        total_pages: 0,
      },
    });

    render(
      <BrowserRouter>
        <TrackSearch />
      </BrowserRouter>,
    );

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

  it('should perform search when query changes', async () => {
    vi.mocked(searchTracks).mockResolvedValue({
      tracks: mockTracks,
      pagination: {
        page: 1,
        limit: 20,
        total: 1,
        total_pages: 1,
      },
    });

    render(
      <BrowserRouter>
        <TrackSearch />
      </BrowserRouter>,
    );

    const input = screen.getByPlaceholderText('Rechercher des tracks...');
    await userEvent.type(input, 'Test');

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

  it('should perform search when search button is clicked', async () => {
    vi.mocked(searchTracks).mockResolvedValue({
      tracks: mockTracks,
      pagination: {
        page: 1,
        limit: 20,
        total: 1,
        total_pages: 1,
      },
    });

    render(
      <BrowserRouter>
        <TrackSearch />
      </BrowserRouter>,
    );

    const input = screen.getByPlaceholderText('Rechercher des tracks...');
    await userEvent.type(input, 'Test');

    const searchButton = screen.getByText('Rechercher');
    await userEvent.click(searchButton);

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

  it('should handle search errors', async () => {
    const error = new TrackSearchError('Search failed', 'NETWORK', true);
    vi.mocked(searchTracks).mockRejectedValue(error);

    render(
      <BrowserRouter>
        <TrackSearch />
      </BrowserRouter>,
    );

    const input = screen.getByPlaceholderText('Rechercher des tracks...');
    await userEvent.type(input, 'Test');

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

    // Error should be displayed
    await waitFor(() => {
      expect(screen.getByText(/Erreur/i)).toBeInTheDocument();
    });
  });

  it('should perform search on Enter key press', async () => {
    vi.mocked(searchTracks).mockResolvedValue({
      tracks: mockTracks,
      pagination: {
        page: 1,
        limit: 20,
        total: 1,
        total_pages: 1,
      },
    });

    render(
      <BrowserRouter>
        <TrackSearch />
      </BrowserRouter>,
    );

    const input = screen.getByPlaceholderText('Rechercher des tracks...');
    await userEvent.type(input, 'Test{Enter}');

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