import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';

import { SrAnnouncer } from './sr-announcer';

describe('SrAnnouncer', () => {
  // ============================================
  // Rendering tests
  // ============================================

  describe('rendering', () => {
    it('renders announcer container', () => {
      const { container } = render(<SrAnnouncer message="Test message" />);

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

    it('renders as div element', () => {
      const { container } = render(<SrAnnouncer message="Test message" />);

      expect(container.firstChild?.nodeName).toBe('DIV');
    });

    it('renders message content', () => {
      render(<SrAnnouncer message="Loading items" />);

      expect(screen.getByText('Loading items')).toBeInTheDocument();
    });

    it('renders empty message without error', () => {
      const { container } = render(<SrAnnouncer message="" />);

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

    it('renders undefined message without error', () => {
      const { container } = render(<SrAnnouncer message={undefined} />);

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

  // ============================================
  // Accessibility tests
  // ============================================

  describe('accessibility', () => {
    it('has role="status"', () => {
      const { container } = render(<SrAnnouncer message="Test" />);

      expect(container.firstChild).toHaveAttribute('role', 'status');
    });

    it('has aria-live="polite" by default', () => {
      const { container } = render(<SrAnnouncer message="Test" />);

      expect(container.firstChild).toHaveAttribute('aria-live', 'polite');
    });

    it('has aria-live="assertive" when assertive prop is true', () => {
      const { container } = render(<SrAnnouncer message="Test" assertive={true} />);

      expect(container.firstChild).toHaveAttribute('aria-live', 'assertive');
    });

    it('has aria-atomic="true"', () => {
      const { container } = render(<SrAnnouncer message="Test" />);

      expect(container.firstChild).toHaveAttribute('aria-atomic', 'true');
    });

    it('is screen-reader only with sr-only class', () => {
      const { container } = render(<SrAnnouncer message="Hidden from view" />);

      expect(container.firstChild).toHaveClass('sr-only');
    });

    it('announces message with proper aria attributes', () => {
      const { container } = render(<SrAnnouncer message="Data loading complete" />);

      const announcer = container.firstChild as HTMLElement;
      expect(announcer).toHaveAttribute('role', 'status');
      expect(announcer).toHaveAttribute('aria-live', 'polite');
      expect(announcer).toHaveAttribute('aria-atomic', 'true');
      expect(announcer).toHaveTextContent('Data loading complete');
    });
  });

  // ============================================
  // HTML attributes tests
  // ============================================

  describe('HTML attributes', () => {
    it('passes data attributes', () => {
      render(<SrAnnouncer message="Test" data-testid="test-announcer" />);

      expect(screen.getByTestId('test-announcer')).toBeInTheDocument();
    });

    it('passes id attribute', () => {
      const { container } = render(<SrAnnouncer message="Test" id="my-announcer" />);

      expect(container.firstChild).toHaveAttribute('id', 'my-announcer');
    });

    it('passes className and merges with sr-only', () => {
      const { container } = render(<SrAnnouncer message="Test" className="custom-class" />);

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

    it('forwards ref correctly', () => {
      const ref = { current: null as HTMLDivElement | null };
      const { container } = render(<SrAnnouncer message="Test" ref={ref} />);

      expect(ref.current).toBe(container.firstChild);
    });
  });

  // ============================================
  // Assertive mode tests
  // ============================================

  describe('assertive announcements', () => {
    it('uses assertive mode for urgent messages', () => {
      const { container } = render(
        <SrAnnouncer message="Error occurred" assertive={true} />,
      );

      expect(container.firstChild).toHaveAttribute('aria-live', 'assertive');
    });

    it('uses polite mode for non-urgent messages', () => {
      const { container } = render(
        <SrAnnouncer message="Data loaded" assertive={false} />,
      );

      expect(container.firstChild).toHaveAttribute('aria-live', 'polite');
    });
  });

  // ============================================
  // Message updates tests
  // ============================================

  describe('message updates', () => {
    it('updates message content', () => {
      const { rerender } = render(<SrAnnouncer message="Initial message" />);

      expect(screen.getByText('Initial message')).toBeInTheDocument();

      rerender(<SrAnnouncer message="Updated message" />);

      expect(screen.queryByText('Initial message')).not.toBeInTheDocument();
      expect(screen.getByText('Updated message')).toBeInTheDocument();
    });

    it('clears message when empty string provided', () => {
      const { rerender, container } = render(<SrAnnouncer message="Message" />);

      expect(screen.getByText('Message')).toBeInTheDocument();

      rerender(<SrAnnouncer message="" />);

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

    it('announces each message update to screen readers', () => {
      const { rerender, container } = render(
        <SrAnnouncer message="Loading..." assertive={true} />,
      );

      expect(container.firstChild).toHaveAttribute('aria-live', 'assertive');
      expect(screen.getByText('Loading...')).toBeInTheDocument();

      rerender(<SrAnnouncer message="Complete!" assertive={true} />);

      expect(container.firstChild).toHaveAttribute('aria-live', 'assertive');
      expect(screen.getByText('Complete!')).toBeInTheDocument();
    });
  });

  // ============================================
  // Common usage patterns tests
  // ============================================

  describe('common patterns', () => {
    it('works for loading announcements', () => {
      const { container, rerender } = render(
        <SrAnnouncer message="Loading items..." />,
      );

      expect(container.firstChild).toHaveAttribute('aria-live', 'polite');
      expect(screen.getByText('Loading items...')).toBeInTheDocument();

      rerender(<SrAnnouncer message="Items loaded successfully" />);

      expect(screen.getByText('Items loaded successfully')).toBeInTheDocument();
    });

    it('works for error announcements', () => {
      const { container } = render(
        <SrAnnouncer message="Error: Failed to save changes" assertive={true} />,
      );

      expect(container.firstChild).toHaveAttribute('aria-live', 'assertive');
      expect(screen.getByText('Error: Failed to save changes')).toBeInTheDocument();
    });

    it('works for success announcements', () => {
      const { container } = render(
        <SrAnnouncer message="Changes saved successfully" />,
      );

      expect(container.firstChild).toHaveAttribute('aria-live', 'polite');
      expect(screen.getByText('Changes saved successfully')).toBeInTheDocument();
    });
  });

  // ============================================
  // Display name tests
  // ============================================

  describe('component metadata', () => {
    it('has correct displayName', () => {
      expect(SrAnnouncer.displayName).toBe('SrAnnouncer');
    });
  });
});
