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

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

describe('BitrateAnalytics', () => {
  const mockAnalytics = {
    total_adaptations: 10,
    reasons: {
      network_slow: 4,
      network_fast: 3,
      buffer_low: 2,
      user_selected: 1,
    },
    adaptations_over_time: [
      { date: '2024-01-01', count: 2 },
      { date: '2024-01-02', count: 3 },
      { date: '2024-01-03', count: 5 },
    ],
    average_bandwidth: 1048576,
  };

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

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

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

    expect(
      screen.getByText("Analytics d'adaptation de bitrate"),
    ).toBeInTheDocument();
    expect(screen.getByRole('status')).toBeInTheDocument(); // LoadingSpinner
  });

  it('should render analytics data when loaded', async () => {
    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      mockAnalytics,
    );

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

    await waitFor(() => {
      expect(screen.getByText('10')).toBeInTheDocument(); // Total adaptations
    });

    expect(screen.getByText("Total d'adaptations")).toBeInTheDocument();
    expect(screen.getByText('1.05 Mbps')).toBeInTheDocument(); // Average bandwidth
    expect(screen.getByText('Raisons différentes')).toBeInTheDocument();
    expect(screen.getByText('4')).toBeInTheDocument(); // Number of reasons
  });

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

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

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

  it('should render chart when adaptations_over_time has data', async () => {
    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      mockAnalytics,
    );

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

    await waitFor(() => {
      expect(screen.getByText('Évolution des adaptations')).toBeInTheDocument();
    });
  });

  it('should render reasons breakdown', async () => {
    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      mockAnalytics,
    );

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

    await waitFor(() => {
      expect(screen.getByText('Répartition par raison')).toBeInTheDocument();
    });

    expect(screen.getByText('Réseau lent')).toBeInTheDocument();
    expect(screen.getByText('Réseau rapide')).toBeInTheDocument();
    expect(screen.getByText('Buffer faible')).toBeInTheDocument();
    expect(screen.getByText('Sélection utilisateur')).toBeInTheDocument();
  });

  it('should display correct counts for each reason', async () => {
    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      mockAnalytics,
    );

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

    await waitFor(() => {
      expect(screen.getByText('4 adaptations')).toBeInTheDocument();
      expect(screen.getByText('3 adaptations')).toBeInTheDocument();
      expect(screen.getByText('2 adaptations')).toBeInTheDocument();
      expect(screen.getByText('1 adaptation')).toBeInTheDocument();
    });
  });

  it('should display percentages for each reason', async () => {
    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      mockAnalytics,
    );

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

    await waitFor(() => {
      expect(screen.getByText('40.0%')).toBeInTheDocument(); // 4/10
      expect(screen.getByText('30.0%')).toBeInTheDocument(); // 3/10
      expect(screen.getByText('20.0%')).toBeInTheDocument(); // 2/10
      expect(screen.getByText('10.0%')).toBeInTheDocument(); // 1/10
    });
  });

  it('should handle empty analytics', async () => {
    const emptyAnalytics = {
      total_adaptations: 0,
      reasons: {},
      adaptations_over_time: [],
    };

    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      emptyAnalytics,
    );

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

    await waitFor(() => {
      expect(
        screen.getByText(/Aucune adaptation de bitrate enregistrée/),
      ).toBeInTheDocument();
    });

    // Vérifier que le total est 0
    const totalElement = screen.getByText("Total d'adaptations").parentElement;
    expect(totalElement).toHaveTextContent('0');
  });

  it('should handle analytics without average_bandwidth', async () => {
    const analyticsWithoutBandwidth = {
      ...mockAnalytics,
      average_bandwidth: undefined,
    };

    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      analyticsWithoutBandwidth,
    );

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

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

    // Should not display bandwidth section
    expect(
      screen.queryByText('Bande passante moyenne'),
    ).not.toBeInTheDocument();
  });

  it('should reload analytics when trackId changes', async () => {
    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      mockAnalytics,
    );

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

    await waitFor(() => {
      expect(bitrateService.getBitrateAnalytics).toHaveBeenCalledWith(1);
    });

    rerender(<BitrateAnalytics trackId={2} />);

    await waitFor(() => {
      expect(bitrateService.getBitrateAnalytics).toHaveBeenCalledWith(2);
    });
  });

  it('should format bandwidth correctly', async () => {
    const analyticsWithDifferentBandwidths = [
      { bandwidth: 1048576, expected: '1.05 Mbps' }, // 1 Mbps
      { bandwidth: 512000, expected: '512.00 Kbps' }, // 512 Kbps
      { bandwidth: 1000, expected: '1.00 Kbps' }, // 1 Kbps
      { bandwidth: 500, expected: '500 bps' }, // 500 bps
    ];

    for (const { bandwidth, expected } of analyticsWithDifferentBandwidths) {
      vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue({
        ...mockAnalytics,
        average_bandwidth: bandwidth,
      });

      const { unmount } = render(<BitrateAnalytics trackId={1} />);

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

      unmount();
    }
  });

  it('should sort reasons by count descending', async () => {
    vi.mocked(bitrateService.getBitrateAnalytics).mockResolvedValue(
      mockAnalytics,
    );

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

    await waitFor(() => {
      expect(screen.getByText('Répartition par raison')).toBeInTheDocument();
    });

    // Vérifier que les raisons sont présentes (le tri est testé indirectement)
    expect(screen.getByText('4 adaptations')).toBeInTheDocument();
    expect(screen.getByText('3 adaptations')).toBeInTheDocument();
    expect(screen.getByText('2 adaptations')).toBeInTheDocument();
    expect(screen.getByText('1 adaptation')).toBeInTheDocument();
  });
});
