import { UserEntity, type UserProps } from '../entities/user.entity';
import { HashedPassword } from '../value-objects/hashed-password.vo';
import { Phone } from '../value-objects/phone.vo';

function createTestUser(overrides: Partial<UserProps> = {}): UserEntity {
  const phone = Phone.create('+84912345678').unwrap();
  const passwordHash = HashedPassword.fromHash('$2b$12$test-hash');

  return new UserEntity('user-1', {
    email: null,
    phone,
    passwordHash,
    fullName: 'Test User',
    avatarUrl: null,
    role: 'AGENT',
    kycStatus: 'NONE',
    kycData: null,
    isActive: true,
    totpSecret: null,
    totpEnabled: false,
    totpBackupCodes: [],
    totpEnabledAt: null,
    ...overrides,
  });
}

describe('UserEntity MFA methods', () => {
  describe('enableTotp', () => {
    it('sets TOTP secret and enables MFA', () => {
      const user = createTestUser();

      expect(user.totpEnabled).toBe(false);
      expect(user.totpSecret).toBeNull();

      user.enableTotp('JBSWY3DPEHPK3PXP', ['hash1', 'hash2']);

      expect(user.totpEnabled).toBe(true);
      expect(user.totpSecret).toBe('JBSWY3DPEHPK3PXP');
      expect(user.totpBackupCodes).toEqual(['hash1', 'hash2']);
      expect(user.totpEnabledAt).toBeInstanceOf(Date);
    });
  });

  describe('disableTotp', () => {
    it('clears TOTP fields', () => {
      const user = createTestUser({
        totpSecret: 'JBSWY3DPEHPK3PXP',
        totpEnabled: true,
        totpBackupCodes: ['hash1'],
        totpEnabledAt: new Date(),
      });

      user.disableTotp();

      expect(user.totpEnabled).toBe(false);
      expect(user.totpSecret).toBeNull();
      expect(user.totpBackupCodes).toEqual([]);
      expect(user.totpEnabledAt).toBeNull();
    });
  });

  describe('consumeBackupCode', () => {
    it('removes the backup code at the given index', () => {
      const user = createTestUser({
        totpBackupCodes: ['hash0', 'hash1', 'hash2', 'hash3'],
      });

      user.consumeBackupCode(1);

      expect(user.totpBackupCodes).toEqual(['hash0', 'hash2', 'hash3']);
    });

    it('removes the first backup code', () => {
      const user = createTestUser({
        totpBackupCodes: ['hash0', 'hash1', 'hash2'],
      });

      user.consumeBackupCode(0);

      expect(user.totpBackupCodes).toEqual(['hash1', 'hash2']);
    });

    it('removes the last backup code', () => {
      const user = createTestUser({
        totpBackupCodes: ['hash0', 'hash1', 'hash2'],
      });

      user.consumeBackupCode(2);

      expect(user.totpBackupCodes).toEqual(['hash0', 'hash1']);
    });
  });

  describe('createNew', () => {
    it('initializes MFA fields to default values', () => {
      const phone = Phone.create('+84912345678').unwrap();
      const passwordHash = HashedPassword.fromHash('$2b$12$test');

      const user = UserEntity.createNew('new-1', phone, 'New User', passwordHash);

      expect(user.totpSecret).toBeNull();
      expect(user.totpEnabled).toBe(false);
      expect(user.totpBackupCodes).toEqual([]);
      expect(user.totpEnabledAt).toBeNull();
    });
  });
});
