import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { PlaybackHeatmap } from './PlaybackHeatmap';
import * as playbackAnalyticsService from '../services/playbackAnalyticsService';

// Mock du service
vi.mock('../services/playbackAnalyticsService', () => ({
  getPlaybackHeatmap: vi.fn(),
}));

describe('PlaybackHeatmap', () => {
  const mockHeatmap: playbackAnalyticsService.PlaybackHeatmap = {
    track_id: 1,
    track_duration: 180,
    segment_size: 5,
    total_sessions: 10,
    max_intensity: 5.0,
    generated_at: '2024-01-01T00:00:00Z',
    segments: [
      {
        start_time: 0,
        end_time: 5,
        listen_count: 10,
        skip_count: 0,
        intensity: 1.0,
        average_play_time: 5.0,
      },
      {
        start_time: 5,
        end_time: 10,
        listen_count: 8,
        skip_count: 2,
        intensity: 0.8,
        average_play_time: 4.0,
      },
      {
        start_time: 10,
        end_time: 15,
        listen_count: 5,
        skip_count: 3,
        intensity: 0.5,
        average_play_time: 2.5,
      },
    ],
  };

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

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should render loading state initially', () => {
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockImplementation(
      () => new Promise(() => {}), // Never resolves
    );

    render(<PlaybackHeatmap trackId={1} />);

    expect(screen.getByText(/Chargement de la heatmap/i)).toBeInTheDocument();
  });

  it('should render heatmap data when loaded', async () => {
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockResolvedValue(
      mockHeatmap,
    );

    render(<PlaybackHeatmap trackId={1} />);

    await waitFor(() => {
      expect(screen.getByText(/Heatmap de Lecture/i)).toBeInTheDocument();
    });

    expect(screen.getByText(/Écoutes totales/i)).toBeInTheDocument();
    expect(screen.getByText(/Skips totales/i)).toBeInTheDocument();
  });

  it('should render error message on error', async () => {
    const errorMessage = 'Failed to load heatmap';
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockRejectedValue(
      new Error(errorMessage),
    );

    render(<PlaybackHeatmap trackId={1} />);

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

  it('should render empty state when no data', async () => {
    const emptyHeatmap: playbackAnalyticsService.PlaybackHeatmap = {
      track_id: 1,
      track_duration: 180,
      segment_size: 5,
      total_sessions: 0,
      max_intensity: 0,
      generated_at: '2024-01-01T00:00:00Z',
      segments: [],
    };

    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockResolvedValue(
      emptyHeatmap,
    );

    render(<PlaybackHeatmap trackId={1} />);

    await waitFor(() => {
      expect(
        screen.getByText(/Aucune donnée de heatmap disponible/i),
      ).toBeInTheDocument();
    });
  });

  it('should call getPlaybackHeatmap with correct parameters', async () => {
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockResolvedValue(
      mockHeatmap,
    );

    render(<PlaybackHeatmap trackId={1} segmentSize={10} />);

    await waitFor(() => {
      expect(playbackAnalyticsService.getPlaybackHeatmap).toHaveBeenCalledWith(
        1,
        10,
      );
    });
  });

  it('should reload heatmap when trackId changes', async () => {
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockResolvedValue(
      mockHeatmap,
    );

    const { rerender } = render(<PlaybackHeatmap trackId={1} />);

    await waitFor(() => {
      expect(playbackAnalyticsService.getPlaybackHeatmap).toHaveBeenCalledWith(
        1,
        5,
      );
    });

    vi.clearAllMocks();
    rerender(<PlaybackHeatmap trackId={2} />);

    await waitFor(() => {
      expect(playbackAnalyticsService.getPlaybackHeatmap).toHaveBeenCalledWith(
        2,
        5,
      );
    });
  });

  it('should display statistics correctly', async () => {
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockResolvedValue(
      mockHeatmap,
    );

    render(<PlaybackHeatmap trackId={1} />);

    await waitFor(() => {
      expect(screen.getByText('23')).toBeInTheDocument(); // Total listens: 10 + 8 + 5
      expect(screen.getByText('5')).toBeInTheDocument(); // Total skips: 0 + 2 + 3
    });
  });

  it('should apply custom className', async () => {
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockResolvedValue(
      mockHeatmap,
    );

    const { container } = render(
      <PlaybackHeatmap trackId={1} className="custom-class" />,
    );

    await waitFor(() => {
      const card = container.querySelector('.custom-class');
      expect(card).toBeInTheDocument();
    });
  });

  it('should handle zero trackId', () => {
    vi.mocked(playbackAnalyticsService.getPlaybackHeatmap).mockResolvedValue(
      mockHeatmap,
    );

    render(<PlaybackHeatmap trackId={0} />);

    // Should not call the service
    expect(playbackAnalyticsService.getPlaybackHeatmap).not.toHaveBeenCalled();
  });
});
