import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { PlayerError } from './PlayerError';

describe('PlayerError', () => {
  it('should not render when error is null', () => {
    const { container } = render(<PlayerError error={null} />);

    expect(container.firstChild).toBeNull();
  });

  it('should render when error is provided', () => {
    const error = new Error('Test error');
    render(<PlayerError error={error} />);

    expect(screen.getByRole('alert')).toBeInTheDocument();
  });

  it('should display error message', () => {
    const error = new Error('Test error');
    render(<PlayerError error={error} />);

    expect(
      screen.getByText('Une erreur est survenue lors de la lecture.'),
    ).toBeInTheDocument();
  });

  it('should display error title', () => {
    const error = new Error('Test error');
    render(<PlayerError error={error} />);

    expect(screen.getByText('Erreur de lecture')).toBeInTheDocument();
  });

  it('should display network error message', () => {
    const error = new Error('Network error');
    error.name = 'NetworkError';
    render(<PlayerError error={error} />);

    expect(
      screen.getByText(
        'Erreur de connexion. Vérifiez votre connexion internet.',
      ),
    ).toBeInTheDocument();
  });

  it('should display decode error message', () => {
    const error = new Error('Decode error');
    error.name = 'DecodeError';
    render(<PlayerError error={error} />);

    expect(
      screen.getByText(
        'Erreur de décodage audio. Le fichier est peut-être corrompu.',
      ),
    ).toBeInTheDocument();
  });

  it('should display source error message', () => {
    const error = new Error('Source not found');
    error.name = 'NotFoundError';
    render(<PlayerError error={error} />);

    expect(
      screen.getByText(
        'Erreur de source audio. Le fichier est introuvable ou inaccessible.',
      ),
    ).toBeInTheDocument();
  });

  it('should display abort error message', () => {
    const error = new Error('Abort error');
    error.name = 'AbortError';
    render(<PlayerError error={error} />);

    expect(screen.getByText('Chargement annulé.')).toBeInTheDocument();
  });

  it('should use custom errorType', () => {
    const error = new Error('Test error');
    render(<PlayerError error={error} errorType="network" />);

    expect(
      screen.getByText(
        'Erreur de connexion. Vérifiez votre connexion internet.',
      ),
    ).toBeInTheDocument();
  });

  it('should display retry button when onRetry is provided', () => {
    const error = new Error('Test error');
    const onRetry = vi.fn();
    render(<PlayerError error={error} onRetry={onRetry} />);

    expect(screen.getByText('Réessayer')).toBeInTheDocument();
  });

  it('should not display retry button when onRetry is not provided', () => {
    const error = new Error('Test error');
    render(<PlayerError error={error} />);

    expect(screen.queryByText('Réessayer')).not.toBeInTheDocument();
  });

  it('should not display retry button when showRetry is false', () => {
    const error = new Error('Test error');
    const onRetry = vi.fn();
    render(<PlayerError error={error} onRetry={onRetry} showRetry={false} />);

    expect(screen.queryByText('Réessayer')).not.toBeInTheDocument();
  });

  it('should call onRetry when retry button is clicked', async () => {
    const user = userEvent.setup();
    const error = new Error('Test error');
    const onRetry = vi.fn();
    render(<PlayerError error={error} onRetry={onRetry} />);

    const retryButton = screen.getByText('Réessayer');
    await user.click(retryButton);

    expect(onRetry).toHaveBeenCalledTimes(1);
  });

  it('should use custom retry label', () => {
    const error = new Error('Test error');
    const onRetry = vi.fn();
    render(<PlayerError error={error} onRetry={onRetry} retryLabel="Retry" />);

    expect(screen.getByText('Retry')).toBeInTheDocument();
  });

  it('should apply custom className', () => {
    const error = new Error('Test error');
    const { container } = render(
      <PlayerError error={error} className="custom-class" />,
    );

    expect(container.firstChild).toHaveClass('custom-class');
  });

  it('should have accessible attributes', () => {
    const error = new Error('Test error');
    render(<PlayerError error={error} />);

    const alert = screen.getByRole('alert');
    expect(alert).toHaveAttribute('aria-live', 'assertive');
  });

  it('should have accessible retry button', () => {
    const error = new Error('Test error');
    const onRetry = vi.fn();
    const { container } = render(
      <PlayerError error={error} onRetry={onRetry} />,
    );

    const retryButton = screen.getByText('Réessayer');
    // Check that aria-label is present on the button element
    const buttonElement = container.querySelector('button[aria-label]');
    expect(buttonElement).toBeInTheDocument();
    expect(buttonElement?.getAttribute('aria-label')).toContain('Réessayer');
  });

  it('should detect network error from message', () => {
    const error = new Error('Network request failed');
    render(<PlayerError error={error} />);

    expect(
      screen.getByText(
        'Erreur de connexion. Vérifiez votre connexion internet.',
      ),
    ).toBeInTheDocument();
  });

  it('should detect decode error from message', () => {
    const error = new Error('Failed to decode audio data');
    render(<PlayerError error={error} />);

    expect(
      screen.getByText(
        'Erreur de décodage audio. Le fichier est peut-être corrompu.',
      ),
    ).toBeInTheDocument();
  });

  it('should detect source error from message', () => {
    const error = new Error('Source not found');
    render(<PlayerError error={error} />);

    expect(
      screen.getByText(
        'Erreur de source audio. Le fichier est introuvable ou inaccessible.',
      ),
    ).toBeInTheDocument();
  });

  it('should detect abort error from message', () => {
    const error = new Error('Request aborted');
    render(<PlayerError error={error} />);

    expect(screen.getByText('Chargement annulé.')).toBeInTheDocument();
  });
});
