/**
 * Unit tests for LanguageSelector component
 *
 * Tests cover:
 * - Rendering both dropdown and inline variants
 * - Current language display
 * - Dropdown open/close functionality
 * - Language selection and change
 * - Available languages display
 * - Flag display
 * - Click outside to close dropdown
 * - Accessibility attributes
 * - Responsive text hiding
 * - Custom className prop
 */

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

// Mock i18n
const mockChangeLanguage = vi.fn();
const mockCurrentLanguage = 'en';

vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string) => key,
    i18n: {
      language: mockCurrentLanguage,
      changeLanguage: mockChangeLanguage,
    },
  }),
}));

// Mock i18n module with supported languages
vi.mock('../../i18n', () => ({
  supportedLanguages: [
    { code: 'en', name: 'English', flag: '🇺🇸' },
    { code: 'es', name: 'Español', flag: '🇪🇸' },
    { code: 'fr', name: 'Français', flag: '🇫🇷' },
    { code: 'de', name: 'Deutsch', flag: '🇩🇪' },
  ],
}));

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

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

  describe('Dropdown Variant (Default)', () => {
    describe('Rendering', () => {
      it('should render the language selector button', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button', { expanded: false });
        expect(button).toBeInTheDocument();
      });

      it('should display current language name on desktop', () => {
        render(<LanguageSelector />);

        const languageName = screen.getByText('English');
        expect(languageName).toBeInTheDocument();
        expect(languageName).toHaveClass('hidden', 'sm:inline');
      });

      it('should display current language flag by default', () => {
        render(<LanguageSelector />);

        const flag = screen.getByText('🇺🇸');
        expect(flag).toBeInTheDocument();
      });

      it('should display Globe icon', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        const svg = button.querySelector('svg');
        expect(svg).toBeInTheDocument();
      });

      it('should display ChevronDown icon', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        const chevron = button.querySelector('svg.w-4.h-4.transition-transform');
        expect(chevron).toBeInTheDocument();
      });

      it('should not display flag when showFlag is false', () => {
        render(<LanguageSelector showFlag={false} />);

        const flag = screen.queryByText('🇺🇸');
        expect(flag).not.toBeInTheDocument();
      });

      it('should not show dropdown by default', () => {
        render(<LanguageSelector />);

        const dropdown = screen.queryByRole('listbox');
        expect(dropdown).not.toBeInTheDocument();
      });
    });

    describe('Dropdown Open/Close', () => {
      it('should open dropdown when button clicked', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const dropdown = screen.getByRole('listbox');
        expect(dropdown).toBeInTheDocument();
        expect(button).toHaveAttribute('aria-expanded', 'true');
      });

      it('should close dropdown when button clicked again', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');

        // Open
        fireEvent.click(button);
        expect(screen.getByRole('listbox')).toBeInTheDocument();

        // Close
        fireEvent.click(button);
        expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
        expect(button).toHaveAttribute('aria-expanded', 'false');
      });

      it('should rotate chevron icon when dropdown is open', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        const chevron = button.querySelector('svg.w-4.h-4.transition-transform');

        // Initially not rotated
        expect(chevron).not.toHaveClass('rotate-180');

        // Open dropdown
        fireEvent.click(button);
        expect(chevron).toHaveClass('rotate-180');
      });

      it('should close dropdown when clicking outside', async () => {
        render(
          <div>
            <LanguageSelector />
            <button>Outside Button</button>
          </div>
        );

        const button = screen.getByRole('button', { expanded: false });
        fireEvent.click(button);

        expect(screen.getByRole('listbox')).toBeInTheDocument();

        // Click outside
        const outsideButton = screen.getByText('Outside Button');
        fireEvent.mouseDown(outsideButton);

        await waitFor(() => {
          expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
        });
      });

      it('should not close dropdown when clicking inside dropdown', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const dropdown = screen.getByRole('listbox');
        fireEvent.mouseDown(dropdown);

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

    describe('Language Selection', () => {
      it('should display all available languages in dropdown', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        expect(screen.getAllByText('English')).toHaveLength(2); // One in button, one in dropdown
        expect(screen.getByText('Español')).toBeInTheDocument();
        expect(screen.getByText('Français')).toBeInTheDocument();
        expect(screen.getByText('Deutsch')).toBeInTheDocument();
      });

      it('should display flags for all languages in dropdown', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        expect(screen.getAllByText('🇺🇸')).toHaveLength(2); // One in button, one in dropdown
        expect(screen.getByText('🇪🇸')).toBeInTheDocument();
        expect(screen.getByText('🇫🇷')).toBeInTheDocument();
        expect(screen.getByText('🇩🇪')).toBeInTheDocument();
      });

      it('should mark current language with Check icon', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const options = screen.getAllByRole('option');
        const englishOption = options.find(opt => opt.textContent?.includes('English'));

        expect(englishOption).toHaveAttribute('aria-selected', 'true');

        // Check icon should be present
        const checkIcon = englishOption?.querySelector('svg.w-4.h-4');
        expect(checkIcon).toBeInTheDocument();
      });

      it('should change language when option clicked', async () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const spanishOption = screen.getAllByRole('option').find(
          opt => opt.textContent?.includes('Español')
        );

        fireEvent.click(spanishOption!);

        await waitFor(() => {
          expect(mockChangeLanguage).toHaveBeenCalledWith('es');
        });
      });

      it('should close dropdown after language selection', async () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const frenchOption = screen.getAllByRole('option').find(
          opt => opt.textContent?.includes('Français')
        );

        fireEvent.click(frenchOption!);

        await waitFor(() => {
          expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
        });
      });

      it('should highlight selected language with brand color', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const options = screen.getAllByRole('option');
        const englishOption = options.find(opt => opt.textContent?.includes('English'));

        expect(englishOption).toHaveClass('bg-brand-50', 'dark:bg-brand-900/20');
        expect(englishOption).toHaveClass('text-brand-700', 'dark:text-brand-300');
      });

      it('should not highlight non-selected languages with brand color', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const options = screen.getAllByRole('option');
        const spanishOption = options.find(opt => opt.textContent?.includes('Español'));

        expect(spanishOption).toHaveClass('text-gray-700', 'dark:text-gray-300');
        expect(spanishOption).not.toHaveClass('bg-brand-50');
      });
    });

    describe('Accessibility', () => {
      it('should have proper ARIA attributes on button', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        expect(button).toHaveAttribute('aria-expanded', 'false');
        expect(button).toHaveAttribute('aria-haspopup', 'listbox');
      });

      it('should update aria-expanded when dropdown opens', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        expect(button).toHaveAttribute('aria-expanded', 'false');

        fireEvent.click(button);
        expect(button).toHaveAttribute('aria-expanded', 'true');
      });

      it('should have aria-label on listbox', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const listbox = screen.getByRole('listbox');
        expect(listbox).toHaveAttribute('aria-label', 'Select language');
      });

      it('should mark language options as selected correctly', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const options = screen.getAllByRole('option');
        const englishOption = options.find(opt => opt.textContent?.includes('English'));
        const spanishOption = options.find(opt => opt.textContent?.includes('Español'));

        expect(englishOption).toHaveAttribute('aria-selected', 'true');
        expect(spanishOption).toHaveAttribute('aria-selected', 'false');
      });
    });

    describe('Styling', () => {
      it('should apply default classes to button', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        expect(button).toHaveClass('flex', 'items-center', 'gap-2');
        expect(button).toHaveClass('px-3', 'py-2');
        expect(button).toHaveClass('rounded-lg');
        expect(button).toHaveClass('transition-colors');
      });

      it('should apply custom className when provided', () => {
        render(<LanguageSelector className="custom-class" />);

        const container = screen.getByRole('button').parentElement;
        expect(container).toHaveClass('custom-class');
      });

      it('should apply dropdown animation classes', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        fireEvent.click(button);

        const dropdown = screen.getByRole('listbox').parentElement;
        expect(dropdown).toHaveClass('animate-in', 'fade-in', 'slide-in-from-top-2');
      });

      it('should apply focus ring on button', () => {
        render(<LanguageSelector />);

        const button = screen.getByRole('button');
        expect(button).toHaveClass('focus:outline-none', 'focus:ring-2', 'focus:ring-brand-500');
      });
    });
  });

  describe('Inline Variant', () => {
    describe('Rendering', () => {
      it('should render inline variant when specified', () => {
        render(<LanguageSelector variant="inline" />);

        // Should show buttons, not a dropdown
        const buttons = screen.getAllByRole('button');
        expect(buttons.length).toBe(4); // One for each language
      });

      it('should display all languages as separate buttons', () => {
        render(<LanguageSelector variant="inline" />);

        expect(screen.getByText('English')).toBeInTheDocument();
        expect(screen.getByText('Español')).toBeInTheDocument();
        expect(screen.getByText('Français')).toBeInTheDocument();
        expect(screen.getByText('Deutsch')).toBeInTheDocument();
      });

      it('should display flags in inline variant by default', () => {
        render(<LanguageSelector variant="inline" />);

        expect(screen.getByText('🇺🇸')).toBeInTheDocument();
        expect(screen.getByText('🇪🇸')).toBeInTheDocument();
        expect(screen.getByText('🇫🇷')).toBeInTheDocument();
        expect(screen.getByText('🇩🇪')).toBeInTheDocument();
      });

      it('should not display flags when showFlag is false', () => {
        render(<LanguageSelector variant="inline" showFlag={false} />);

        expect(screen.queryByText('🇺🇸')).not.toBeInTheDocument();
        expect(screen.queryByText('🇪🇸')).not.toBeInTheDocument();
      });

      it('should highlight current language button', () => {
        render(<LanguageSelector variant="inline" />);

        const englishButton = screen.getByRole('button', { name: /English/i });
        expect(englishButton).toHaveClass('bg-brand-600', 'text-white');
      });

      it('should not highlight non-selected language buttons', () => {
        render(<LanguageSelector variant="inline" />);

        const spanishButton = screen.getByRole('button', { name: /Español/i });
        expect(spanishButton).toHaveClass('bg-gray-100', 'text-gray-700');
        expect(spanishButton).not.toHaveClass('bg-brand-600');
      });
    });

    describe('Language Selection', () => {
      it('should change language when button clicked', async () => {
        render(<LanguageSelector variant="inline" />);

        const frenchButton = screen.getByRole('button', { name: /Français/i });
        fireEvent.click(frenchButton);

        await waitFor(() => {
          expect(mockChangeLanguage).toHaveBeenCalledWith('fr');
        });
      });

      it('should change language for each available language', async () => {
        render(<LanguageSelector variant="inline" />);

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

        await waitFor(() => {
          expect(mockChangeLanguage).toHaveBeenCalledWith('de');
        });
      });
    });

    describe('Styling', () => {
      it('should apply flex layout classes', () => {
        const { container } = render(<LanguageSelector variant="inline" />);

        const wrapper = container.firstChild;
        expect(wrapper).toHaveClass('flex', 'flex-wrap', 'gap-2');
      });

      it('should apply custom className when provided', () => {
        const { container } = render(<LanguageSelector variant="inline" className="my-custom-class" />);

        const wrapper = container.firstChild;
        expect(wrapper).toHaveClass('my-custom-class');
      });

      it('should apply button styling classes', () => {
        render(<LanguageSelector variant="inline" />);

        const buttons = screen.getAllByRole('button');
        buttons.forEach(button => {
          expect(button).toHaveClass('px-3', 'py-1.5', 'rounded-lg', 'text-sm', 'font-medium', 'transition-colors');
        });
      });

      it('should apply hover classes to non-selected buttons', () => {
        render(<LanguageSelector variant="inline" />);

        const spanishButton = screen.getByRole('button', { name: /Español/i });
        expect(spanishButton).toHaveClass('hover:bg-gray-200', 'dark:hover:bg-gray-600');
      });
    });
  });

  describe('Integration', () => {
    it('should render correctly with all dropdown props together', () => {
      render(
        <LanguageSelector
          variant="dropdown"
          showFlag={true}
          className="custom-class"
        />
      );

      const button = screen.getByRole('button');
      expect(button).toBeInTheDocument();
      expect(screen.getByText('English')).toBeInTheDocument();
      expect(screen.getByText('🇺🇸')).toBeInTheDocument();

      const container = button.parentElement;
      expect(container).toHaveClass('custom-class');
    });

    it('should render correctly with all inline props together', () => {
      const { container } = render(
        <LanguageSelector
          variant="inline"
          showFlag={true}
          className="inline-custom"
        />
      );

      const wrapper = container.firstChild;
      expect(wrapper).toHaveClass('inline-custom');

      const buttons = screen.getAllByRole('button');
      expect(buttons.length).toBe(4);

      expect(screen.getByText('🇺🇸')).toBeInTheDocument();
      expect(screen.getByText('English')).toBeInTheDocument();
    });

    it('should maintain dropdown functionality across re-renders', () => {
      const { rerender } = render(<LanguageSelector />);

      const button = screen.getByRole('button');
      fireEvent.click(button);
      expect(screen.getByRole('listbox')).toBeInTheDocument();

      rerender(<LanguageSelector className="updated" />);
      expect(screen.getByRole('listbox')).toBeInTheDocument();
    });
  });

  describe('Edge Cases', () => {
    it('should handle missing language gracefully', () => {
      // The component should fall back to the first language if current language is not found
      render(<LanguageSelector />);

      // Should still render without crashing
      const button = screen.getByRole('button');
      expect(button).toBeInTheDocument();
    });

    it('should cleanup event listener on unmount', () => {
      const { unmount } = render(<LanguageSelector />);

      const removeEventListenerSpy = vi.spyOn(document, 'removeEventListener');
      unmount();

      expect(removeEventListenerSpy).toHaveBeenCalledWith('mousedown', expect.any(Function));
    });

    it('should not call changeLanguage when clicking current language', async () => {
      render(<LanguageSelector variant="inline" />);

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

      await waitFor(() => {
        expect(mockChangeLanguage).toHaveBeenCalledWith('en');
      });

      // Even if clicking the current language, it still calls changeLanguage
      // This is expected behavior (idempotent)
    });
  });
});
