// src/utils/authUtils.test.ts
import { describe, it, expect, vi } from 'vitest';
import zxcvbn from 'zxcvbn';
import { validatePasswordStrength } from './authUtils';

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

// Helper function to create a complete mock zxcvbn result, satisfying the type.
const createMockZxcvbnResult = (
  score: 0 | 1 | 2 | 3 | 4,
  suggestions: string[] = [],
): zxcvbn.ZXCVBNResult => ({
  score,
  feedback: {
    suggestions,
    warning: '',
  },
  // Add dummy values for the other required properties to satisfy the type.
  guesses: 1,
  guesses_log10: 1,
  crack_times_seconds: {
    online_throttling_100_per_hour: 1,
    online_no_throttling_10_per_second: 1,
    offline_slow_hashing_1e4_per_second: 1,
    offline_fast_hashing_1e10_per_second: 1,
  },
  crack_times_display: {
    online_throttling_100_per_hour: '1 second',
    online_no_throttling_10_per_second: '1 second',
    offline_slow_hashing_1e4_per_second: '1 second',
    offline_fast_hashing_1e10_per_second: '1 second',
  },
  sequence: [],
  calc_time: 1,
});

describe('validatePasswordStrength', () => {
  it('should return invalid for a very weak password (score 0)', () => {
    // Arrange: Mock zxcvbn to return a score of 0 and specific feedback
    vi.mocked(zxcvbn).mockReturnValue(
      createMockZxcvbnResult(0, ['Add more words', 'Use a longer password']),
    );

    // Act
    const result = validatePasswordStrength('password');

    // Assert
    expect(result.isValid).toBe(false);
    expect(result.feedback).toBe('Password is too weak. Add more words Use a longer password');
  });

  it('should return invalid for a weak password (score 1)', () => {
    // Arrange: Mock zxcvbn to return a score of 1
    vi.mocked(zxcvbn).mockReturnValue(createMockZxcvbnResult(1, ['Avoid common words']));

    // Act
    const result = validatePasswordStrength('password123');

    // Assert
    expect(result.isValid).toBe(false);
    expect(result.feedback).toBe('Password is too weak. Avoid common words');
  });

  it('should return invalid for a medium password (score 2)', () => {
    // Arrange: Mock zxcvbn to return a score of 2
    vi.mocked(zxcvbn).mockReturnValue(
      createMockZxcvbnResult(2, ['Add another symbol or number']),
    );

    // Act
    const result = validatePasswordStrength('Password123');

    // Assert
    expect(result.isValid).toBe(false);
    expect(result.feedback).toBe('Password is too weak. Add another symbol or number');
  });

  it('should return valid for a good password (score 3)', () => {
    // Arrange: Mock zxcvbn to return a score of 3 (the minimum required)
    vi.mocked(zxcvbn).mockReturnValue(createMockZxcvbnResult(3));

    // Act
    const result = validatePasswordStrength('a-Strong-Password!');

    // Assert
    expect(result.isValid).toBe(true);
    expect(result.feedback).toBe('');
  });

  it('should return valid for a very strong password (score 4)', () => {
    // Arrange: Mock zxcvbn to return a score of 4
    vi.mocked(zxcvbn).mockReturnValue(createMockZxcvbnResult(4));

    // Act
    const result = validatePasswordStrength('a-Very-Strong-Password-123!');

    // Assert
    expect(result.isValid).toBe(true);
    expect(result.feedback).toBe('');
  });
});