/**
 * Tests for ConnectionStatus Component
 */

import { render, screen, fireEvent } from '@testing-library/react';
import { ConnectionStatus } from '@/components/events/ConnectionStatus';
import type { SSEError } from '@/lib/types/events';

describe('ConnectionStatus', () => {
  const mockOnReconnect = jest.fn();

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

  describe('connected state', () => {
    it('renders connected status', () => {
      render(<ConnectionStatus state="connected" />);

      expect(screen.getByText('Connected')).toBeInTheDocument();
      expect(screen.getByText('Receiving real-time updates')).toBeInTheDocument();
    });

    it('does not show reconnect button when connected', () => {
      render(<ConnectionStatus state="connected" onReconnect={mockOnReconnect} />);

      expect(screen.queryByRole('button', { name: /reconnect/i })).not.toBeInTheDocument();
    });

    it('applies connected styling', () => {
      const { container } = render(<ConnectionStatus state="connected" />);

      expect(container.querySelector('.border-green-200')).toBeInTheDocument();
    });
  });

  describe('connecting state', () => {
    it('renders connecting status', () => {
      render(<ConnectionStatus state="connecting" />);

      expect(screen.getByText('Connecting')).toBeInTheDocument();
      expect(screen.getByText('Establishing connection...')).toBeInTheDocument();
    });

    it('shows retry count when retrying', () => {
      render(<ConnectionStatus state="connecting" retryCount={3} />);

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

  describe('disconnected state', () => {
    it('renders disconnected status', () => {
      render(<ConnectionStatus state="disconnected" />);

      expect(screen.getByText('Disconnected')).toBeInTheDocument();
      expect(screen.getByText('Not connected to server')).toBeInTheDocument();
    });

    it('shows reconnect button when disconnected', () => {
      render(<ConnectionStatus state="disconnected" onReconnect={mockOnReconnect} />);

      const button = screen.getByRole('button', { name: /reconnect/i });
      expect(button).toBeInTheDocument();
    });

    it('calls onReconnect when button is clicked', () => {
      render(<ConnectionStatus state="disconnected" onReconnect={mockOnReconnect} />);

      const button = screen.getByRole('button', { name: /reconnect/i });
      fireEvent.click(button);

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

  describe('error state', () => {
    it('renders error status', () => {
      render(<ConnectionStatus state="error" />);

      expect(screen.getByText('Connection Error')).toBeInTheDocument();
      expect(screen.getByText('Failed to connect')).toBeInTheDocument();
    });

    it('shows reconnect button when in error state', () => {
      render(<ConnectionStatus state="error" onReconnect={mockOnReconnect} />);

      const button = screen.getByRole('button', { name: /reconnect/i });
      expect(button).toBeInTheDocument();
    });

    it('applies error styling', () => {
      const { container } = render(<ConnectionStatus state="error" />);

      expect(container.querySelector('.border-destructive')).toBeInTheDocument();
    });
  });

  describe('error details', () => {
    const mockError: SSEError = {
      message: 'Connection timeout',
      code: 'TIMEOUT',
      timestamp: '2024-01-15T10:30:00Z',
      retryAttempt: 2,
    };

    it('shows error message when error is provided', () => {
      render(<ConnectionStatus state="error" error={mockError} />);

      expect(screen.getByText(/Error: Connection timeout/)).toBeInTheDocument();
    });

    it('shows error code when provided', () => {
      render(<ConnectionStatus state="error" error={mockError} />);

      expect(screen.getByText(/Code: TIMEOUT/)).toBeInTheDocument();
    });

    it('hides error details when showErrorDetails is false', () => {
      render(<ConnectionStatus state="error" error={mockError} showErrorDetails={false} />);

      expect(screen.queryByText(/Error: Connection timeout/)).not.toBeInTheDocument();
    });
  });

  describe('compact mode', () => {
    it('renders compact version', () => {
      const { container } = render(<ConnectionStatus state="connected" compact />);

      // Compact mode should not have the full description
      expect(screen.queryByText('Receiving real-time updates')).not.toBeInTheDocument();
      // Should still show the label
      expect(screen.getByText('Connected')).toBeInTheDocument();
      // Should use smaller container
      expect(container.querySelector('.rounded-lg')).not.toBeInTheDocument();
    });

    it('shows compact reconnect button when disconnected', () => {
      render(<ConnectionStatus state="disconnected" onReconnect={mockOnReconnect} compact />);

      // Should have a small reconnect button
      const button = screen.getByRole('button', { name: /reconnect/i });
      expect(button).toBeInTheDocument();
      expect(button.className).toContain('h-6');
    });

    it('shows retry count in compact mode', () => {
      render(<ConnectionStatus state="connecting" retryCount={5} compact />);

      expect(screen.getByText(/retry 5/i)).toBeInTheDocument();
    });
  });

  describe('showReconnectButton prop', () => {
    it('hides reconnect button when showReconnectButton is false', () => {
      render(
        <ConnectionStatus
          state="disconnected"
          onReconnect={mockOnReconnect}
          showReconnectButton={false}
        />
      );

      expect(screen.queryByRole('button', { name: /reconnect/i })).not.toBeInTheDocument();
    });
  });

  describe('accessibility', () => {
    it('has role="status" for screen readers', () => {
      render(<ConnectionStatus state="connected" />);

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

    it('has aria-live="polite" for status updates', () => {
      render(<ConnectionStatus state="connected" />);

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

  describe('className prop', () => {
    it('applies custom className', () => {
      const { container } = render(
        <ConnectionStatus state="connected" className="custom-class" />
      );

      expect(container.querySelector('.custom-class')).toBeInTheDocument();
    });
  });
});
