/**
 * Comprehensive Unit Tests for Validation Schemas
 *
 * These tests ensure proper input validation and content filtering
 */

import { describe, it, expect } from 'vitest';
import {
  usernameSchema,
  displayNameSchema,
  passwordSchema,
  bioSchema,
  personalLocationSchema,
  preferredPronounsSchema,
  profileEditSchema,
} from '@/lib/validation';
import { z } from 'zod';

describe('usernameSchema', () => {
  describe('Valid Usernames', () => {
    it('should accept valid username with letters and numbers', () => {
      const result = usernameSchema.safeParse('user123');
      expect(result.success).toBe(true);
      if (result.success) {
        expect(result.data).toBe('user123');
      }
    });

    it('should accept username with hyphens', () => {
      const result = usernameSchema.safeParse('user-name');
      expect(result.success).toBe(true);
    });

    it('should accept username with underscores', () => {
      const result = usernameSchema.safeParse('user_name');
      expect(result.success).toBe(true);
    });

    it('should accept minimum length username (3 chars)', () => {
      const result = usernameSchema.safeParse('abc');
      expect(result.success).toBe(true);
    });

    it('should accept maximum length username (30 chars)', () => {
      const result = usernameSchema.safeParse('a'.repeat(30));
      expect(result.success).toBe(true);
    });

    it('should convert username to lowercase', () => {
      const result = usernameSchema.safeParse('UserName123');
      expect(result.success).toBe(true);
      if (result.success) {
        expect(result.data).toBe('username123');
      }
    });

    it('should accept username starting and ending with alphanumeric', () => {
      const result = usernameSchema.safeParse('a-b_c-d1');
      expect(result.success).toBe(true);
    });
  });

  describe('Invalid Usernames', () => {
    it('should reject username shorter than 3 characters', () => {
      const result = usernameSchema.safeParse('ab');
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('at least 3 characters');
      }
    });

    it('should reject username longer than 30 characters', () => {
      const result = usernameSchema.safeParse('a'.repeat(31));
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('less than 30 characters');
      }
    });

    it('should reject username starting with hyphen', () => {
      const result = usernameSchema.safeParse('-username');
      expect(result.success).toBe(false);
    });

    it('should reject username starting with underscore', () => {
      const result = usernameSchema.safeParse('_username');
      expect(result.success).toBe(false);
    });

    it('should reject username ending with hyphen', () => {
      const result = usernameSchema.safeParse('username-');
      expect(result.success).toBe(false);
    });

    it('should reject username ending with underscore', () => {
      const result = usernameSchema.safeParse('username_');
      expect(result.success).toBe(false);
    });

    it('should reject username with consecutive hyphens', () => {
      const result = usernameSchema.safeParse('user--name');
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('consecutive');
      }
    });

    it('should reject username with consecutive underscores', () => {
      const result = usernameSchema.safeParse('user__name');
      expect(result.success).toBe(false);
    });

    it('should reject username with special characters', () => {
      const result = usernameSchema.safeParse('user@name');
      expect(result.success).toBe(false);
    });

    it('should reject username with spaces', () => {
      const result = usernameSchema.safeParse('user name');
      expect(result.success).toBe(false);
    });

    it('should reject username with dots', () => {
      const result = usernameSchema.safeParse('user.name');
      expect(result.success).toBe(false);
    });
  });

  describe('Forbidden Usernames - Security', () => {
    it('should reject "admin"', () => {
      const result = usernameSchema.safeParse('admin');
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('not allowed');
      }
    });

    it('should reject "administrator"', () => {
      const result = usernameSchema.safeParse('administrator');
      expect(result.success).toBe(false);
    });

    it('should reject "moderator"', () => {
      const result = usernameSchema.safeParse('moderator');
      expect(result.success).toBe(false);
    });

    it('should reject "root"', () => {
      const result = usernameSchema.safeParse('root');
      expect(result.success).toBe(false);
    });

    it('should reject "system"', () => {
      const result = usernameSchema.safeParse('system');
      expect(result.success).toBe(false);
    });

    it('should reject offensive username', () => {
      const result = usernameSchema.safeParse('nazi');
      expect(result.success).toBe(false);
    });

    it('should reject case-insensitive forbidden username', () => {
      const result = usernameSchema.safeParse('ADMIN');
      expect(result.success).toBe(false);
    });

    it('should reject mixed-case forbidden username', () => {
      const result = usernameSchema.safeParse('AdMiN');
      expect(result.success).toBe(false);
    });
  });
});

describe('displayNameSchema', () => {
  describe('Valid Display Names', () => {
    it('should accept valid display name', () => {
      const result = displayNameSchema.safeParse('John Doe');
      expect(result.success).toBe(true);
    });

    it('should accept display name with special characters', () => {
      const result = displayNameSchema.safeParse('O\'Brien');
      expect(result.success).toBe(true);
    });

    it('should accept display name with numbers', () => {
      const result = displayNameSchema.safeParse('User 123');
      expect(result.success).toBe(true);
    });

    it('should accept Unicode characters', () => {
      const result = displayNameSchema.safeParse('José García 日本');
      expect(result.success).toBe(true);
    });

    it('should accept emojis', () => {
      const result = displayNameSchema.safeParse('Cool User 😎');
      expect(result.success).toBe(true);
    });

    it('should accept undefined (optional field)', () => {
      const result = displayNameSchema.safeParse(undefined);
      expect(result.success).toBe(true);
    });

    it('should accept empty string', () => {
      const result = displayNameSchema.safeParse('');
      expect(result.success).toBe(true);
    });
  });

  describe('Invalid Display Names', () => {
    it('should reject display name longer than 100 characters', () => {
      const result = displayNameSchema.safeParse('a'.repeat(101));
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('less than 100 characters');
      }
    });

    it('should reject display name with "nazi"', () => {
      const result = displayNameSchema.safeParse('NaziSymbol');
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('inappropriate content');
      }
    });

    it('should reject display name with "hitler"', () => {
      const result = displayNameSchema.safeParse('hitler fan');
      expect(result.success).toBe(false);
    });

    it('should reject display name with offensive terms (case insensitive)', () => {
      const result = displayNameSchema.safeParse('TERRORIST group');
      expect(result.success).toBe(false);
    });
  });
});

describe('passwordSchema', () => {
  describe('Valid Passwords', () => {
    it('should accept strong password with all requirements', () => {
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: 'NewPass123!',
        confirmPassword: 'NewPass123!',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(true);
    });

    it('should accept password with multiple special characters', () => {
      const data = {
        currentPassword: 'Old123!@#',
        newPassword: 'New123!@#$%',
        confirmPassword: 'New123!@#$%',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(true);
    });

    it('should accept maximum length password (128 chars)', () => {
      const pwd = 'A1!' + 'a'.repeat(125);
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: pwd,
        confirmPassword: pwd,
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(true);
    });
  });

  describe('Invalid Passwords - Complexity Requirements', () => {
    it('should reject password shorter than 8 characters', () => {
      const data = {
        currentPassword: 'Old123!',
        newPassword: 'New12!',
        confirmPassword: 'New12!',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('at least 8 characters');
      }
    });

    it('should reject password longer than 128 characters', () => {
      const pwd = 'A'.repeat(129);
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: pwd,
        confirmPassword: pwd,
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
    });

    it('should reject password without uppercase letter', () => {
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: 'newpass123!',
        confirmPassword: 'newpass123!',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
      if (!result.success) {
        const messages = result.error.issues.map(i => i.message).join(' ');
        expect(messages).toContain('uppercase letter');
      }
    });

    it('should reject password without lowercase letter', () => {
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: 'NEWPASS123!',
        confirmPassword: 'NEWPASS123!',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
      if (!result.success) {
        const messages = result.error.issues.map(i => i.message).join(' ');
        expect(messages).toContain('lowercase letter');
      }
    });

    it('should reject password without number', () => {
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: 'NewPassword!',
        confirmPassword: 'NewPassword!',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
      if (!result.success) {
        const messages = result.error.issues.map(i => i.message).join(' ');
        expect(messages).toContain('number');
      }
    });

    it('should reject password without special character', () => {
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: 'NewPass123',
        confirmPassword: 'NewPass123',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
      if (!result.success) {
        const messages = result.error.issues.map(i => i.message).join(' ');
        expect(messages).toContain('special character');
      }
    });

    it('should reject mismatched passwords', () => {
      const data = {
        currentPassword: 'OldPass123!',
        newPassword: 'NewPass123!',
        confirmPassword: 'DifferentPass123!',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain("don't match");
      }
    });

    it('should reject empty current password', () => {
      const data = {
        currentPassword: '',
        newPassword: 'NewPass123!',
        confirmPassword: 'NewPass123!',
      };
      const result = passwordSchema.safeParse(data);
      expect(result.success).toBe(false);
    });
  });
});

describe('bioSchema', () => {
  describe('Valid Bios', () => {
    it('should accept valid bio', () => {
      const result = bioSchema.safeParse('Software developer from NYC');
      expect(result.success).toBe(true);
    });

    it('should accept bio with newlines', () => {
      const result = bioSchema.safeParse('Line 1\nLine 2');
      expect(result.success).toBe(true);
    });

    it('should accept bio with emojis', () => {
      const result = bioSchema.safeParse('Developer 💻 Coffee lover ☕');
      expect(result.success).toBe(true);
    });

    it('should accept maximum length bio (500 chars)', () => {
      const result = bioSchema.safeParse('a'.repeat(500));
      expect(result.success).toBe(true);
    });

    it('should accept undefined (optional field)', () => {
      const result = bioSchema.safeParse(undefined);
      expect(result.success).toBe(true);
    });

    it('should trim whitespace', () => {
      const result = bioSchema.safeParse('  Bio text  ');
      expect(result.success).toBe(true);
      if (result.success) {
        expect(result.data).toBe('Bio text');
      }
    });
  });

  describe('Invalid Bios', () => {
    it('should reject bio longer than 500 characters', () => {
      const result = bioSchema.safeParse('a'.repeat(501));
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('less than 500 characters');
      }
    });

    it('should reject bio with HTML tags (< and >)', () => {
      const result = bioSchema.safeParse('Bio with <script>alert(1)</script>');
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('HTML tags');
      }
    });

    it('should reject bio with angle brackets', () => {
      const result = bioSchema.safeParse('5 < 10 and 10 > 5');
      expect(result.success).toBe(false);
    });
  });
});

describe('personalLocationSchema', () => {
  describe('Valid Locations', () => {
    it('should accept valid location', () => {
      const result = personalLocationSchema.safeParse('New York, USA');
      expect(result.success).toBe(true);
    });

    it('should accept location with special characters', () => {
      const result = personalLocationSchema.safeParse('São Paulo, Brazil');
      expect(result.success).toBe(true);
    });

    it('should accept maximum length location (100 chars)', () => {
      const result = personalLocationSchema.safeParse('a'.repeat(100));
      expect(result.success).toBe(true);
    });

    it('should accept undefined (optional field)', () => {
      const result = personalLocationSchema.safeParse(undefined);
      expect(result.success).toBe(true);
    });

    it('should trim whitespace', () => {
      const result = personalLocationSchema.safeParse('  Tokyo  ');
      expect(result.success).toBe(true);
      if (result.success) {
        expect(result.data).toBe('Tokyo');
      }
    });
  });

  describe('Invalid Locations', () => {
    it('should reject location longer than 100 characters', () => {
      const result = personalLocationSchema.safeParse('a'.repeat(101));
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('less than 100 characters');
      }
    });

    it('should reject location with angle brackets', () => {
      const result = personalLocationSchema.safeParse('<New York>');
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('special characters');
      }
    });

    it('should reject location with curly braces', () => {
      const result = personalLocationSchema.safeParse('Location {test}');
      expect(result.success).toBe(false);
    });
  });
});

describe('preferredPronounsSchema', () => {
  describe('Valid Pronouns', () => {
    it('should accept valid pronouns', () => {
      const result = preferredPronounsSchema.safeParse('they/them');
      expect(result.success).toBe(true);
    });

    it('should accept he/him', () => {
      const result = preferredPronounsSchema.safeParse('he/him');
      expect(result.success).toBe(true);
    });

    it('should accept she/her', () => {
      const result = preferredPronounsSchema.safeParse('she/her');
      expect(result.success).toBe(true);
    });

    it('should accept custom pronouns', () => {
      const result = preferredPronounsSchema.safeParse('xe/xem');
      expect(result.success).toBe(true);
    });

    it('should accept maximum length pronouns (20 chars)', () => {
      const result = preferredPronounsSchema.safeParse('a'.repeat(20));
      expect(result.success).toBe(true);
    });

    it('should accept undefined (optional field)', () => {
      const result = preferredPronounsSchema.safeParse(undefined);
      expect(result.success).toBe(true);
    });

    it('should trim whitespace', () => {
      const result = preferredPronounsSchema.safeParse('  they/them  ');
      expect(result.success).toBe(true);
      if (result.success) {
        expect(result.data).toBe('they/them');
      }
    });
  });

  describe('Invalid Pronouns', () => {
    it('should reject pronouns longer than 20 characters', () => {
      const result = preferredPronounsSchema.safeParse('a'.repeat(21));
      expect(result.success).toBe(false);
      if (!result.success) {
        expect(result.error.issues[0].message).toContain('less than 20 characters');
      }
    });
  });
});

describe('profileEditSchema', () => {
  describe('Valid Profiles', () => {
    it('should accept valid complete profile', () => {
      const data = {
        username: 'testuser',
        display_name: 'Test User',
        bio: 'Software developer',
      };
      const result = profileEditSchema.safeParse(data);
      expect(result.success).toBe(true);
    });

    it('should accept profile with optional fields omitted', () => {
      const data = {
        username: 'testuser',
      };
      const result = profileEditSchema.safeParse(data);
      expect(result.success).toBe(true);
    });

    it('should normalize username to lowercase', () => {
      const data = {
        username: 'TestUser',
        display_name: 'Test User',
      };
      const result = profileEditSchema.safeParse(data);
      expect(result.success).toBe(true);
      if (result.success) {
        expect(result.data.username).toBe('testuser');
      }
    });
  });

  describe('Invalid Profiles', () => {
    it('should reject profile with invalid username', () => {
      const data = {
        username: 'admin', // Forbidden
        display_name: 'Test User',
      };
      const result = profileEditSchema.safeParse(data);
      expect(result.success).toBe(false);
    });

    it('should reject profile with offensive display name', () => {
      const data = {
        username: 'testuser',
        display_name: 'nazi sympathizer',
      };
      const result = profileEditSchema.safeParse(data);
      expect(result.success).toBe(false);
    });

    it('should reject profile with HTML in bio', () => {
      const data = {
        username: 'testuser',
        bio: 'Bio with <script>alert(1)</script>',
      };
      const result = profileEditSchema.safeParse(data);
      expect(result.success).toBe(false);
    });

    it('should reject profile with missing required username', () => {
      const data = {
        display_name: 'Test User',
      };
      const result = profileEditSchema.safeParse(data);
      expect(result.success).toBe(false);
    });
  });
});
