import { describe, it, expect } from 'vitest';
import {
  validatePasswordStrength,
  calculatePasswordStrength,
} from './passwordValidator';

describe('passwordValidator', () => {
  describe('validatePasswordStrength', () => {
    it('should validate a password with all requirements', () => {
      const result = validatePasswordStrength('SecurePass123!');
      expect(result.isValid).toBe(true);
      expect(result.errors).toHaveLength(0);
      expect(result.strength.length).toBe(true);
      expect(result.strength.upper).toBe(true);
      expect(result.strength.lower).toBe(true);
      expect(result.strength.number).toBe(true);
      expect(result.strength.special).toBe(true);
    });

    it('should reject password shorter than 8 characters', () => {
      const result = validatePasswordStrength('Test123');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain('password must be at least 8 characters');
      expect(result.strength.length).toBe(false);
    });

    it('should reject password longer than 128 characters', () => {
      const longPassword = `${'A'.repeat(129)}a1!`;
      const result = validatePasswordStrength(longPassword);
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain(
        'password must be less than 128 characters',
      );
    });

    it('should reject password without uppercase letter', () => {
      const result = validatePasswordStrength('test123!@#');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain(
        'password must contain at least one uppercase letter',
      );
      expect(result.strength.upper).toBe(false);
    });

    it('should reject password without lowercase letter', () => {
      const result = validatePasswordStrength('TEST123!@#');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain(
        'password must contain at least one lowercase letter',
      );
      expect(result.strength.lower).toBe(false);
    });

    it('should reject password without number', () => {
      const result = validatePasswordStrength('TestPass!@#');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain(
        'password must contain at least one number',
      );
      expect(result.strength.number).toBe(false);
    });

    it('should reject password without special character', () => {
      const result = validatePasswordStrength('TestPass123');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain(
        'password must contain at least one special character',
      );
      expect(result.strength.special).toBe(false);
    });

    it('should accept password exactly 8 characters', () => {
      const result = validatePasswordStrength('Test123!');
      expect(result.isValid).toBe(true);
      expect(result.errors).toHaveLength(0);
    });

    it('should return multiple errors for password missing multiple requirements', () => {
      const result = validatePasswordStrength('test');
      expect(result.isValid).toBe(false);
      expect(result.errors.length).toBeGreaterThan(1);
    });

    it('should validate password with various special characters', () => {
      const specialChars = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'];
      specialChars.forEach((char) => {
        const password = `Test123${char}`;
        const result = validatePasswordStrength(password);
        expect(result.isValid).toBe(true);
        expect(result.strength.special).toBe(true);
      });
    });
  });

  describe('calculatePasswordStrength', () => {
    it('should return score 5 for strong password', () => {
      const score = calculatePasswordStrength('SecurePass123!');
      expect(score).toBe(5);
    });

    it('should return score 0 for empty password', () => {
      const score = calculatePasswordStrength('');
      expect(score).toBe(0);
    });

    it('should return score 2 for password with length and lowercase', () => {
      const score = calculatePasswordStrength('testpass');
      expect(score).toBe(2); // length + lowercase
    });

    it('should return score 2 for password with length and uppercase', () => {
      const score = calculatePasswordStrength('TESTPASS');
      expect(score).toBe(2);
    });

    it('should return score 3 for password with length, uppercase, and lowercase', () => {
      const score = calculatePasswordStrength('TestPass');
      expect(score).toBe(3);
    });

    it('should return score 4 for password with length, uppercase, lowercase, and number', () => {
      const score = calculatePasswordStrength('TestPass123');
      expect(score).toBe(4);
    });
  });
});
