import { describe, expect, it } from 'vitest';
import { UserRole } from '../value-objects/UserRole';
import { AdminUser } from './AdminUser';

describe('AdminUser', () => {
  describe('TDD - Test First', () => {
    it('should create a valid admin user', () => {
      // Arrange & Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'admin@example.com',
        displayName: 'Admin User',
        roles: ['owner'],
        status: 'active',
      });

      // Assert
      expect(user.id.value).toBe('user-123');
      expect(user.email.value).toBe('admin@example.com');
      expect(user.displayName).toBe('Admin User');
      expect(user.roles).toHaveLength(1);
      expect(user.roles[0]!.value).toBe('owner');
      expect(user.status.value).toBe('active');
    });

    it('should validate email format', () => {
      // Arrange & Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'invalid-email',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      // Assert - Email should be created but validation happens in value object
      expect(user.email.value).toBe('invalid-email');
    });

    it('should detect system admin (owner)', () => {
      // Arrange
      const owner = AdminUser.create({
        id: 'owner-1',
        email: 'owner@example.com',
        displayName: 'Owner',
        roles: ['owner'],
        status: 'active',
      });

      const admin = AdminUser.create({
        id: 'admin-1',
        email: 'admin@example.com',
        displayName: 'Admin',
        roles: ['admin'],
        status: 'active',
      });

      const user = AdminUser.create({
        id: 'user-1',
        email: 'user@example.com',
        displayName: 'User',
        roles: ['user'],
        status: 'active',
      });

      // Assert
      expect(owner.isSystemAdmin()).toBe(true);
      expect(admin.isSystemAdmin()).toBe(true);
      expect(user.isSystemAdmin()).toBe(false);
    });

    it('should handle multiple roles', () => {
      // Arrange & Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'multi@example.com',
        displayName: 'Multi Role',
        roles: ['owner', 'admin'],
        status: 'active',
      });

      // Assert
      expect(user.roles).toHaveLength(2);
      expect(user.roles.map(r => r.value)).toContain('owner');
      expect(user.roles.map(r => r.value)).toContain('admin');
    });

    it('should handle suspended status', () => {
      // Arrange & Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'suspended@example.com',
        displayName: 'Suspended User',
        roles: ['user'],
        status: 'suspended',
      });

      // Assert
      expect(user.status.value).toBe('suspended');
      expect(user.isActive()).toBe(false);
    });

    it('should handle optional fields', () => {
      // Arrange & Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'minimal@example.com',
        displayName: 'Minimal User',
        roles: ['user'],
        status: 'active',
      });

      // Assert
      expect(user.primaryDriverId).toBeUndefined();
      expect(user.lastLoginAt).toBeUndefined();
    });

    it('should handle all optional fields', () => {
      // Arrange
      const now = new Date();

      // Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'full@example.com',
        displayName: 'Full User',
        roles: ['user'],
        status: 'active',
        primaryDriverId: 'driver-456',
        lastLoginAt: now,
      });

      // Assert
      expect(user.primaryDriverId).toBe('driver-456');
      expect(user.lastLoginAt).toEqual(now);
    });

    it('should handle createdAt and updatedAt', () => {
      // Arrange & Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      // Assert
      expect(user.createdAt).toBeInstanceOf(Date);
      expect(user.updatedAt).toBeInstanceOf(Date);
    });

    it('should handle role assignment with validation', () => {
      // Arrange & Act
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      // Assert - Should accept any role string (validation happens in value object)
      expect(user.roles).toHaveLength(1);
      expect(user.roles[0]!.value).toBe('user');
    });

    it('should handle status changes', () => {
      // Arrange
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      // Act - Use domain method to change status
      user.suspend();

      // Assert
      expect(user.status.value).toBe('suspended');
    });

    it('should check if user is active', () => {
      // Arrange
      const activeUser = AdminUser.create({
        id: 'user-123',
        email: 'active@example.com',
        displayName: 'Active User',
        roles: ['user'],
        status: 'active',
      });

      const suspendedUser = AdminUser.create({
        id: 'user-456',
        email: 'suspended@example.com',
        displayName: 'Suspended User',
        roles: ['user'],
        status: 'suspended',
      });

      // Assert
      expect(activeUser.isActive()).toBe(true);
      expect(suspendedUser.isActive()).toBe(false);
    });

    it('should handle role management', () => {
      // Arrange
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      // Act
      user.addRole(UserRole.fromString('admin'));

      // Assert
      expect(user.roles).toHaveLength(2);
      expect(user.hasRole('admin')).toBe(true);
    });

    it('should handle display name updates', () => {
      // Arrange
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Old Name',
        roles: ['user'],
        status: 'active',
      });

      // Act
      user.updateDisplayName('New Name');

      // Assert
      expect(user.displayName).toBe('New Name');
    });

    it('should handle login recording', () => {
      // Arrange
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      const beforeLogin = user.lastLoginAt;

      // Act
      user.recordLogin();

      // Assert
      expect(user.lastLoginAt).toBeDefined();
      expect(user.lastLoginAt).not.toEqual(beforeLogin);
    });

    it('should handle summary generation', () => {
      // Arrange
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['owner'],
        status: 'active',
        lastLoginAt: new Date(),
      });

      // Act
      const summary = user.toSummary();

      // Assert
      expect(summary.id).toBe('user-123');
      expect(summary.email).toBe('test@example.com');
      expect(summary.displayName).toBe('Test User');
      expect(summary.roles).toEqual(['owner']);
      expect(summary.status).toBe('active');
      expect(summary.isSystemAdmin).toBe(true);
      expect(summary.lastLoginAt).toBeDefined();
    });

    it('should handle equality comparison', () => {
      // Arrange
      const user1 = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      const user2 = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['user'],
        status: 'active',
      });

      const user3 = AdminUser.create({
        id: 'user-456',
        email: 'other@example.com',
        displayName: 'Other User',
        roles: ['user'],
        status: 'active',
      });

      // Assert
      expect(user1.equals(user2)).toBe(true);
      expect(user1.equals(user3)).toBe(false);
      expect(user1.equals(undefined)).toBe(false);
    });

    it('should handle management permissions', () => {
      // Arrange
      const owner = AdminUser.create({
        id: 'owner-1',
        email: 'owner@example.com',
        displayName: 'Owner',
        roles: ['owner'],
        status: 'active',
      });

      const admin = AdminUser.create({
        id: 'admin-1',
        email: 'admin@example.com',
        displayName: 'Admin',
        roles: ['admin'],
        status: 'active',
      });

      const user = AdminUser.create({
        id: 'user-1',
        email: 'user@example.com',
        displayName: 'User',
        roles: ['user'],
        status: 'active',
      });

      // Assert - Owner can manage everyone
      expect(owner.canManage(admin)).toBe(true);
      expect(owner.canManage(user)).toBe(true);
      expect(owner.canManage(owner)).toBe(true); // Can manage self

      // Admin can manage users but not admins/owners
      expect(admin.canManage(user)).toBe(true);
      expect(admin.canManage(admin)).toBe(false);
      expect(admin.canManage(owner)).toBe(false);

      // User cannot manage anyone except self
      expect(user.canManage(user)).toBe(true);
      expect(user.canManage(admin)).toBe(false);
      expect(user.canManage(owner)).toBe(false);
    });

    it('should handle role modification permissions', () => {
      // Arrange
      const owner = AdminUser.create({
        id: 'owner-1',
        email: 'owner@example.com',
        displayName: 'Owner',
        roles: ['owner'],
        status: 'active',
      });

      const admin = AdminUser.create({
        id: 'admin-1',
        email: 'admin@example.com',
        displayName: 'Admin',
        roles: ['admin'],
        status: 'active',
      });

      const user = AdminUser.create({
        id: 'user-1',
        email: 'user@example.com',
        displayName: 'User',
        roles: ['user'],
        status: 'active',
      });

      // Assert - Only owner can modify roles
      expect(owner.canModifyRoles(user)).toBe(true);
      expect(owner.canModifyRoles(admin)).toBe(true);
      expect(owner.canModifyRoles(owner)).toBe(false); // Cannot modify own roles

      expect(admin.canModifyRoles(user)).toBe(false);
      expect(user.canModifyRoles(user)).toBe(false);
    });

    it('should handle status change permissions', () => {
      // Arrange
      const owner = AdminUser.create({
        id: 'owner-1',
        email: 'owner@example.com',
        displayName: 'Owner',
        roles: ['owner'],
        status: 'active',
      });

      const admin = AdminUser.create({
        id: 'admin-1',
        email: 'admin@example.com',
        displayName: 'Admin',
        roles: ['admin'],
        status: 'active',
      });

      const user = AdminUser.create({
        id: 'user-1',
        email: 'user@example.com',
        displayName: 'User',
        roles: ['user'],
        status: 'active',
      });

      // Assert - Owner can change anyone's status
      expect(owner.canChangeStatus(user)).toBe(true);
      expect(owner.canChangeStatus(admin)).toBe(true);
      expect(owner.canChangeStatus(owner)).toBe(false); // Cannot change own status

      // Admin can change user status but not admin/owner
      expect(admin.canChangeStatus(user)).toBe(true);
      expect(admin.canChangeStatus(admin)).toBe(false);
      expect(admin.canChangeStatus(owner)).toBe(false);

      // User cannot change status
      expect(user.canChangeStatus(user)).toBe(false);
      expect(user.canChangeStatus(admin)).toBe(false);
      expect(user.canChangeStatus(owner)).toBe(false);
    });

    it('should handle deletion permissions', () => {
      // Arrange
      const owner = AdminUser.create({
        id: 'owner-1',
        email: 'owner@example.com',
        displayName: 'Owner',
        roles: ['owner'],
        status: 'active',
      });

      const admin = AdminUser.create({
        id: 'admin-1',
        email: 'admin@example.com',
        displayName: 'Admin',
        roles: ['admin'],
        status: 'active',
      });

      const user = AdminUser.create({
        id: 'user-1',
        email: 'user@example.com',
        displayName: 'User',
        roles: ['user'],
        status: 'active',
      });

      // Assert - Owner can delete anyone except self
      expect(owner.canDelete(user)).toBe(true);
      expect(owner.canDelete(admin)).toBe(true);
      expect(owner.canDelete(owner)).toBe(false); // Cannot delete self

      // Admin can delete users but not admins/owners
      expect(admin.canDelete(user)).toBe(true);
      expect(admin.canDelete(admin)).toBe(false);
      expect(admin.canDelete(owner)).toBe(false);

      // User cannot delete anyone
      expect(user.canDelete(user)).toBe(false);
      expect(user.canDelete(admin)).toBe(false);
      expect(user.canDelete(owner)).toBe(false);
    });

    it('should handle authority comparison', () => {
      // Arrange
      const owner = AdminUser.create({
        id: 'owner-1',
        email: 'owner@example.com',
        displayName: 'Owner',
        roles: ['owner'],
        status: 'active',
      });

      const admin = AdminUser.create({
        id: 'admin-1',
        email: 'admin@example.com',
        displayName: 'Admin',
        roles: ['admin'],
        status: 'active',
      });

      const user = AdminUser.create({
        id: 'user-1',
        email: 'user@example.com',
        displayName: 'User',
        roles: ['user'],
        status: 'active',
      });

      // Assert
      expect(owner.hasHigherAuthorityThan(admin)).toBe(true);
      expect(owner.hasHigherAuthorityThan(user)).toBe(true);
      expect(admin.hasHigherAuthorityThan(user)).toBe(true);
      expect(admin.hasHigherAuthorityThan(owner)).toBe(false);
      expect(user.hasHigherAuthorityThan(admin)).toBe(false);
    });

    it('should handle role display names', () => {
      // Arrange
      const user = AdminUser.create({
        id: 'user-123',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['owner', 'admin'],
        status: 'active',
      });

      // Act
      const displayNames = user.getRoleDisplayNames();

      // Assert
      expect(displayNames).toContain('Owner');
      expect(displayNames).toContain('Admin');
    });
  });
});