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

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

// 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('PlaylistRecommendations', () => {
  const mockRecommendations = [
    {
      playlist: {
        id: 1,
        user_id: 1,
        title: 'Recommended 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',
      } as Playlist,
      score: 0.85,
      reason: 'Similaire aux playlists suivies',
    },
    {
      playlist: {
        id: 2,
        user_id: 2,
        title: 'Recommended Playlist 2',
        description: 'Description 2',
        is_public: true,
        cover_url: '',
        track_count: 3,
        followers_count: 5,
        created_at: '2024-01-02T00:00:00Z',
        updated_at: '2024-01-02T00:00:00Z',
      } as Playlist,
      score: 0.72,
      reason: 'Populaire',
    },
  ];

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

  it('should render loading state', () => {
    mockGetPlaylistRecommendations.mockImplementation(
      () =>
        new Promise((resolve) =>
          setTimeout(
            () =>
              resolve({
                recommendations: mockRecommendations,
                count: 2,
              }),
            100,
          ),
        ),
    );

    render(<PlaylistRecommendations />);

    expect(
      screen.getByRole('status') || document.querySelector('.animate-spin'),
    ).toBeInTheDocument();
  });

  it('should display recommendations', async () => {
    mockGetPlaylistRecommendations.mockResolvedValue({
      recommendations: mockRecommendations,
      count: 2,
    });

    render(<PlaylistRecommendations />);

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

    expect(screen.getByText('Recommandations pour vous')).toBeInTheDocument();
    expect(screen.getByText('2 playlists recommandées')).toBeInTheDocument();
  });

  it('should display recommendation scores', async () => {
    mockGetPlaylistRecommendations.mockResolvedValue({
      recommendations: mockRecommendations,
      count: 2,
    });

    render(<PlaylistRecommendations />);

    await waitFor(() => {
      expect(screen.getByText('85%')).toBeInTheDocument();
      expect(screen.getByText('72%')).toBeInTheDocument();
    });
  });

  it('should display recommendation reasons', async () => {
    mockGetPlaylistRecommendations.mockResolvedValue({
      recommendations: mockRecommendations,
      count: 2,
    });

    render(<PlaylistRecommendations />);

    await waitFor(() => {
      expect(
        screen.getByText('Similaire aux playlists suivies'),
      ).toBeInTheDocument();
      expect(screen.getByText('Populaire')).toBeInTheDocument();
    });
  });

  it('should handle empty recommendations', async () => {
    mockGetPlaylistRecommendations.mockResolvedValue({
      recommendations: [],
      count: 0,
    });

    render(<PlaylistRecommendations />);

    await waitFor(() => {
      expect(
        screen.getByText('Aucune recommandation disponible pour le moment'),
      ).toBeInTheDocument();
    });
  });

  it('should handle errors', async () => {
    const errorMessage = 'Erreur de chargement';
    mockGetPlaylistRecommendations.mockRejectedValue(new Error(errorMessage));

    render(<PlaylistRecommendations />);

    await waitFor(() => {
      expect(screen.getByText(errorMessage)).toBeInTheDocument();
    });
  });

  it('should call onPlaylistClick when playlist is clicked', async () => {
    const onPlaylistClick = jest.fn();
    mockGetPlaylistRecommendations.mockResolvedValue({
      recommendations: [mockRecommendations[0]],
      count: 1,
    });

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

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

  it('should pass correct parameters to getPlaylistRecommendations', async () => {
    mockGetPlaylistRecommendations.mockResolvedValue({
      recommendations: [],
      count: 0,
    });

    render(
      <PlaylistRecommendations limit={10} minScore={0.5} includeOwn={true} />,
    );

    await waitFor(() => {
      expect(mockGetPlaylistRecommendations).toHaveBeenCalledWith({
        limit: 10,
        min_score: 0.5,
        include_own: true,
      });
    });
  });

  it('should use default parameters', async () => {
    mockGetPlaylistRecommendations.mockResolvedValue({
      recommendations: [],
      count: 0,
    });

    render(<PlaylistRecommendations />);

    await waitFor(() => {
      expect(mockGetPlaylistRecommendations).toHaveBeenCalledWith({
        limit: 20,
        min_score: 0.1,
        include_own: false,
      });
    });
  });
});
