// src/pages/admin/components/PasswordStrengthIndicator.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi, type Mock } from 'vitest';
import { PasswordStrengthIndicator } from './PasswordStrengthIndicator';
import zxcvbn from 'zxcvbn';

// Mock the zxcvbn library to control its output for testing
vi.mock('zxcvbn');

describe('PasswordStrengthIndicator', () => {
  it('should render 5 gray bars when no password is provided', () => {
    (zxcvbn as Mock).mockReturnValue({ score: -1, feedback: { warning: '', suggestions: [] } });
    const { container } = render(<PasswordStrengthIndicator password="" />);
    const bars = container.querySelectorAll('.h-1\\.5');
    expect(bars).toHaveLength(5);
    bars.forEach((bar) => {
      expect(bar).toHaveClass('bg-gray-200');
    });
    expect(screen.queryByText(/Very Weak/i)).not.toBeInTheDocument();
  });

  it.each([
    { score: 0, label: 'Very Weak', color: 'bg-red-500', bars: 1 },
    { score: 1, label: 'Weak', color: 'bg-red-500', bars: 2 },
    { score: 2, label: 'Fair', color: 'bg-orange-500', bars: 3 },
    { score: 3, label: 'Good', color: 'bg-yellow-500', bars: 4 },
    { score: 4, label: 'Strong', color: 'bg-green-500', bars: 5 },
  ])('should render correctly for score $score ($label)', ({ score, label, color, bars }) => {
    (zxcvbn as Mock).mockReturnValue({ score, feedback: { warning: '', suggestions: [] } });
    const { container } = render(<PasswordStrengthIndicator password="some-password" />);

    // Check the label
    expect(screen.getByText(label)).toBeInTheDocument();

    // Check the bar colors
    const barElements = container.querySelectorAll('.h-1\\.5');
    expect(barElements).toHaveLength(5);

    for (let i = 0; i < 5; i++) {
      if (i < bars) {
        expect(barElements[i]).toHaveClass(color);
      } else {
        expect(barElements[i]).toHaveClass('bg-gray-200');
      }
    }
  });

  it('should display a warning from zxcvbn', () => {
    (zxcvbn as Mock).mockReturnValue({
      score: 1,
      feedback: {
        warning: 'This is a very common password',
        suggestions: [],
      },
    });
    render(<PasswordStrengthIndicator password="password" />);
    expect(screen.getByText(/this is a very common password/i)).toBeInTheDocument();
  });

  it('should display a suggestion from zxcvbn', () => {
    (zxcvbn as Mock).mockReturnValue({
      score: 1,
      feedback: {
        warning: '',
        suggestions: ['Add another word or two'],
      },
    });
    render(<PasswordStrengthIndicator password="pass" />);
    expect(screen.getByText(/add another word or two/i)).toBeInTheDocument();
  });

  it('should prioritize warning over suggestions', () => {
    (zxcvbn as Mock).mockReturnValue({
      score: 1,
      feedback: { warning: 'A warning here', suggestions: ['A suggestion here'] },
    });
    render(<PasswordStrengthIndicator password="password" />);
    expect(screen.getByText(/a warning here/i)).toBeInTheDocument();
    expect(screen.queryByText(/a suggestion here/i)).not.toBeInTheDocument();
  });

  it('should use default empty string if password prop is undefined', () => {
    (zxcvbn as Mock).mockReturnValue({ score: 0, feedback: { warning: '', suggestions: [] } });
    const { container } = render(<PasswordStrengthIndicator />);
    const bars = container.querySelectorAll('.h-1\\.5');
    expect(bars).toHaveLength(5);
    bars.forEach((bar) => {
      expect(bar).toHaveClass('bg-gray-200');
    });
    expect(screen.queryByText(/Very Weak/i)).not.toBeInTheDocument();
  });

  it('should handle out-of-range scores gracefully (defensive)', () => {
    // Mock a score that isn't 0-4 to hit default switch cases
    (zxcvbn as Mock).mockReturnValue({ score: 99, feedback: { warning: '', suggestions: [] } });
    const { container } = render(<PasswordStrengthIndicator password="test" />);

    // Check bars - should hit default case in getBarColor which returns gray
    const bars = container.querySelectorAll('.h-1\\.5');
    bars.forEach((bar) => {
      expect(bar).toHaveClass('bg-gray-200');
    });

    // Check label - should hit default case in getStrengthLabel which returns empty string
    const labelSpan = container.querySelector('span.font-bold');
    expect(labelSpan).toHaveTextContent('');
  });
});
