/**
 * CopySuccessToast Component Tests
 *
 * Tests for CopySuccessToast component covering:
 * - Rendering with default props
 * - Custom message display
 * - Auto-dismiss functionality
 * - Close button functionality
 * - Accessibility (ARIA attributes)
 * - Haptic feedback on mobile
 */

import { render, screen, waitFor, fireEvent, getByRole } from '@testing-library/react';
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { CopySuccessToast, useCopySuccessToast } from './CopySuccessToast';

// Mock navigator.vibrate
Object.assign(navigator, {
  vibrate: vi.fn(),
});

describe('CopySuccessToast', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

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

  describe('Rendering', () => {
    it('should render with default message', () => {
      const { rerender } = render(
        <CopySuccessToast show={true} onClose={() => {}} />
      );

      // Use the toast-message id to be specific
      const messageElement = document.getElementById('toast-message');
      expect(messageElement).toHaveTextContent('Copied to clipboard!');
      expect(screen.getByRole('alert')).toBeInTheDocument();
    });

    it('should render with custom message', () => {
      render(
        <CopySuccessToast
          show={true}
          message="Draft saved to history!"
          onClose={() => {}}
        />
      );

      // Use id to be more specific
      const messageElement = document.getElementById('toast-message');
      expect(messageElement).toHaveTextContent('Draft saved to history!');
    });

    it('should not render when show is false', () => {
      render(
        <CopySuccessToast show={false} onClose={() => {}} />
      );

      expect(screen.queryByRole('alert')).not.toBeInTheDocument();
    });

    it('should render with dismiss button', () => {
      render(
        <CopySuccessToast show={true} onClose={() => {}} />
      );

      const dismissButton = screen.getByLabelText('Dismiss notification');
      expect(dismissButton).toBeInTheDocument();
    });
  });

  describe('Accessibility', () => {
    it('should have proper ARIA attributes', () => {
      render(
        <CopySuccessToast
          show={true}
          message="Test message"
          onClose={() => {}}
        />
      );

      const alert = screen.getByRole('alert');
      expect(alert).toHaveAttribute('aria-describedby', 'toast-message');

      const message = document.getElementById('toast-message');
      expect(message).toHaveTextContent('Test message');
      expect(message).toHaveAttribute('id', 'toast-message');
    });

    it('should announce to screen readers via live region', () => {
      render(
        <CopySuccessToast
          show={true}
          message="Copied!"
          onClose={() => {}}
        />
      );

      const liveRegion = screen.getByRole('status');
      expect(liveRegion).toHaveAttribute('aria-live', 'polite');
      expect(liveRegion).toHaveAttribute('aria-atomic', 'true');
      expect(liveRegion).toHaveTextContent('Copied!');
    });

    it('should clear live region message when hidden', async () => {
      const { rerender } = render(
        <CopySuccessToast
          show={true}
          message="Visible message"
          onClose={() => {}}
        />
      );

      const liveRegion = screen.getByRole('status');
      expect(liveRegion).toHaveTextContent('Visible message');

      rerender(
        <CopySuccessToast
          show={false}
          message="Visible message"
          onClose={() => {}}
        />
      );

      await waitFor(() => {
        expect(liveRegion).toHaveTextContent('');
      });
    });
  });

  describe('Auto-dismiss', () => {
    it('should auto-dismiss after default duration (3000ms)', async () => {
      vi.useFakeTimers();

      const onClose = vi.fn();
      render(
        <CopySuccessToast show={true} onClose={onClose} />
      );

      // Initially visible
      expect(screen.getByRole('alert')).toBeInTheDocument();

      // Fast-forward past 3000ms
      vi.advanceTimersByTime(3500);

      // Run all pending timers
      await vi.runAllTimersAsync();

      expect(onClose).toHaveBeenCalled();

      vi.useRealTimers();
    });

    it('should auto-dismiss after custom duration', async () => {
      vi.useFakeTimers();

      const onClose = vi.fn();
      render(
        <CopySuccessToast
          show={true}
          onClose={onClose}
          duration={1000}
        />
      );

      vi.advanceTimersByTime(1500);
      await vi.runAllTimersAsync();

      expect(onClose).toHaveBeenCalled();

      vi.useRealTimers();
    });
  });

  describe('Close button', () => {
    it('should call onClose when dismiss button is clicked', async () => {
      vi.useFakeTimers();

      const onClose = vi.fn();
      render(
        <CopySuccessToast show={true} onClose={onClose} />
      );

      const dismissButton = screen.getByLabelText('Dismiss notification');
      fireEvent.click(dismissButton);

      // Advance time for exit animation (300ms)
      vi.advanceTimersByTime(350);
      await vi.runAllTimersAsync();

      expect(onClose).toHaveBeenCalled();

      vi.useRealTimers();
    });

    it('should hide toast when dismiss button is clicked', async () => {
      const onClose = vi.fn();
      render(
        <CopySuccessToast show={true} onClose={onClose} />
      );

      const dismissButton = screen.getByLabelText('Dismiss notification');

      // Initially visible
      expect(screen.getByRole('alert')).toBeInTheDocument();

      fireEvent.click(dismissButton);

      // The toast should fade out
      await waitFor(() => {
        expect(screen.getByRole('alert')).toHaveClass(/opacity-0/);
      });
    });
  });

  describe('Haptic feedback', () => {
    it('should trigger vibration on mobile when shown', () => {
      render(
        <CopySuccessToast show={true} onClose={() => {}} />
      );

      expect(navigator.vibrate).toHaveBeenCalledWith(50);
    });

    it('should not trigger vibration when hidden', () => {
      render(
        <CopySuccessToast show={false} onClose={() => {}} />
      );

      expect(navigator.vibrate).not.toHaveBeenCalled();
    });

    it('should not trigger vibration when navigator.vibrate is unavailable', () => {
      // @ts-expect-error - Testing missing vibrate API
      const originalVibrate = navigator.vibrate;
      delete navigator.vibrate;

      render(
        <CopySuccessToast show={true} onClose={() => {}} />
      );

      // Should not throw error
      expect(screen.getByRole('alert')).toBeInTheDocument();

      navigator.vibrate = originalVibrate;
    });
  });

  describe('useCopySuccessToast hook', () => {
    it('should provide showToast and hideToast functions', async () => {
      const TestComponent = () => {
        const { showToast, hideToast, show } = useCopySuccessToast();

        return (
          <div>
            <span data-testid="show-state">{show ? 'visible' : 'hidden'}</span>
            <button onClick={() => showToast()}>Show</button>
            <button onClick={() => hideToast()}>Hide</button>
            <CopySuccessToast show={show} onClose={hideToast} />
          </div>
        );
      };

      render(<TestComponent />);

      expect(screen.getByTestId('show-state')).toHaveTextContent('hidden');

      const showButton = screen.getByText('Show');
      await fireEvent.click(showButton);

      await waitFor(() => {
        expect(screen.getByTestId('show-state')).toHaveTextContent('visible');
      });
    });

    it('should allow custom message in showToast', async () => {
      const TestComponent = () => {
        const { showToast, show, message: hookMessage } = useCopySuccessToast();

        return (
          <div>
            <button onClick={() => showToast('Custom message!')}>
              Show Custom
            </button>
            <CopySuccessToast show={show} message={hookMessage} onClose={() => {}} />
          </div>
        );
      };

      render(<TestComponent />);

      const button = screen.getByText('Show Custom');
      fireEvent.click(button);

      // Use id to be more specific
      const messageElement = document.getElementById('toast-message');
      await waitFor(() => {
        expect(messageElement).toHaveTextContent('Custom message!');
      }, { timeout: 3000 });
    });
  });

  describe('Confetti animation', () => {
    it('should render confetti pieces when shown', () => {
      render(
        <CopySuccessToast show={true} onClose={() => {}} />
      );

      // Confetti container should be present
      const confettiContainer = document.querySelector('[aria-hidden="true"]');
      expect(confettiContainer).toBeInTheDocument();
    });

    it('should not render confetti when hidden', () => {
      render(
        <CopySuccessToast show={false} onClose={() => {}} />
      );

      const confettiContainer = document.querySelector('[aria-hidden="true"]');
      expect(confettiContainer).not.toBeInTheDocument();
    });
  });
});
