/**
 * Zulip账号关联实体测试
 * 
 * 功能描述：
 * - 测试实体的业务方法逻辑
 * - 验证状态管理和判断方法
 * - 测试时间相关的业务逻辑
 * - 验证错误处理和重试机制
 * 
 * 测试范围：
 * - 状态判断方法（isActive, isHealthy, canBeDeleted等）
 * - 时间相关方法（isStale, needsVerification等）
 * - 状态更新方法（activate, suspend, deactivate等）
 * - 错误处理方法（setError, clearError等）
 * 
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 创建测试文件，确保实体业务方法的测试覆盖 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.0.0
 * @since 2026-01-12
 * @lastModified 2026-01-12
 */

import { ZulipAccounts } from './zulip_accounts.entity';
import { 
  DEFAULT_MAX_RETRY_COUNT, 
  HIGH_RETRY_THRESHOLD, 
  DEFAULT_MAX_AGE_DAYS, 
  DEFAULT_VERIFICATION_HOURS,
  MILLISECONDS_PER_DAY,
  MILLISECONDS_PER_HOUR
} from './zulip_accounts.constants';

describe('ZulipAccounts Entity', () => {
  let entity: ZulipAccounts;

  beforeEach(() => {
    entity = new ZulipAccounts();
    entity.id = BigInt(1);
    entity.gameUserId = BigInt(123);
    entity.zulipUserId = 12345;
    entity.zulipEmail = 'test@example.com';
    entity.zulipFullName = 'Test User';
    entity.zulipApiKeyEncrypted = 'encrypted-key';
    entity.status = 'active';
    entity.retryCount = 0;
    entity.errorMessage = null;
    entity.createdAt = new Date();
    entity.updatedAt = new Date();
    entity.lastVerifiedAt = new Date();
    entity.lastSyncedAt = new Date();
  });

  describe('isActive()', () => {
    it('should return true when status is active', () => {
      entity.status = 'active';
      expect(entity.isActive()).toBe(true);
    });

    it('should return false when status is not active', () => {
      entity.status = 'inactive';
      expect(entity.isActive()).toBe(false);

      entity.status = 'suspended';
      expect(entity.isActive()).toBe(false);

      entity.status = 'error';
      expect(entity.isActive()).toBe(false);
    });
  });

  describe('isHealthy()', () => {
    it('should return true when status is active and retry count is low', () => {
      entity.status = 'active';
      entity.retryCount = 0;
      expect(entity.isHealthy()).toBe(true);

      entity.retryCount = DEFAULT_MAX_RETRY_COUNT - 1;
      expect(entity.isHealthy()).toBe(true);
    });

    it('should return false when status is not active', () => {
      entity.status = 'inactive';
      entity.retryCount = 0;
      expect(entity.isHealthy()).toBe(false);

      entity.status = 'error';
      entity.retryCount = 0;
      expect(entity.isHealthy()).toBe(false);
    });

    it('should return false when retry count exceeds limit', () => {
      entity.status = 'active';
      entity.retryCount = DEFAULT_MAX_RETRY_COUNT;
      expect(entity.isHealthy()).toBe(false);

      entity.retryCount = DEFAULT_MAX_RETRY_COUNT + 1;
      expect(entity.isHealthy()).toBe(false);
    });
  });

  describe('canBeDeleted()', () => {
    it('should return true when status is not active', () => {
      entity.status = 'inactive';
      entity.retryCount = 0;
      expect(entity.canBeDeleted()).toBe(true);

      entity.status = 'suspended';
      entity.retryCount = 0;
      expect(entity.canBeDeleted()).toBe(true);

      entity.status = 'error';
      entity.retryCount = 0;
      expect(entity.canBeDeleted()).toBe(true);
    });

    it('should return true when retry count exceeds high threshold', () => {
      entity.status = 'active';
      entity.retryCount = HIGH_RETRY_THRESHOLD + 1;
      expect(entity.canBeDeleted()).toBe(true);
    });

    it('should return false when status is active and retry count is low', () => {
      entity.status = 'active';
      entity.retryCount = 0;
      expect(entity.canBeDeleted()).toBe(false);

      entity.retryCount = HIGH_RETRY_THRESHOLD;
      expect(entity.canBeDeleted()).toBe(false);
    });
  });

  describe('isStale()', () => {
    it('should return false for recently updated entity', () => {
      entity.updatedAt = new Date(); // 刚刚更新
      expect(entity.isStale()).toBe(false);
    });

    it('should return true for old entity using default max age', () => {
      const oldDate = new Date();
      oldDate.setTime(oldDate.getTime() - (DEFAULT_MAX_AGE_DAYS * MILLISECONDS_PER_DAY + 1000));
      entity.updatedAt = oldDate;
      expect(entity.isStale()).toBe(true);
    });

    it('should return false for entity within default max age', () => {
      const recentDate = new Date();
      recentDate.setTime(recentDate.getTime() - (DEFAULT_MAX_AGE_DAYS * MILLISECONDS_PER_DAY - 1000));
      entity.updatedAt = recentDate;
      expect(entity.isStale()).toBe(false);
    });

    it('should respect custom max age parameter', () => {
      const customMaxAge = 2 * MILLISECONDS_PER_DAY; // 2天
      const oldDate = new Date();
      oldDate.setTime(oldDate.getTime() - (customMaxAge + 1000));
      entity.updatedAt = oldDate;
      
      expect(entity.isStale(customMaxAge)).toBe(true);
    });

    it('should handle edge case at exact max age boundary', () => {
      const exactDate = new Date();
      exactDate.setTime(exactDate.getTime() - (DEFAULT_MAX_AGE_DAYS * MILLISECONDS_PER_DAY));
      entity.updatedAt = exactDate;
      expect(entity.isStale()).toBe(false); // 等于边界值应该返回false
    });
  });

  describe('needsVerification()', () => {
    it('should return true when lastVerifiedAt is null', () => {
      entity.lastVerifiedAt = null;
      expect(entity.needsVerification()).toBe(true);
    });

    it('should return false for recently verified entity', () => {
      entity.lastVerifiedAt = new Date(); // 刚刚验证
      expect(entity.needsVerification()).toBe(false);
    });

    it('should return true for old verification using default max age', () => {
      const oldDate = new Date();
      oldDate.setTime(oldDate.getTime() - (DEFAULT_VERIFICATION_HOURS * MILLISECONDS_PER_HOUR + 1000));
      entity.lastVerifiedAt = oldDate;
      expect(entity.needsVerification()).toBe(true);
    });

    it('should return false for verification within default max age', () => {
      const recentDate = new Date();
      recentDate.setTime(recentDate.getTime() - (DEFAULT_VERIFICATION_HOURS * MILLISECONDS_PER_HOUR - 1000));
      entity.lastVerifiedAt = recentDate;
      expect(entity.needsVerification()).toBe(false);
    });

    it('should respect custom max age parameter', () => {
      const customMaxAge = 2 * MILLISECONDS_PER_HOUR; // 2小时
      const oldDate = new Date();
      oldDate.setTime(oldDate.getTime() - (customMaxAge + 1000));
      entity.lastVerifiedAt = oldDate;
      
      expect(entity.needsVerification(customMaxAge)).toBe(true);
    });
  });

  describe('shouldRetry()', () => {
    it('should return true when status is error and retry count is below limit', () => {
      entity.status = 'error';
      entity.retryCount = 0;
      expect(entity.shouldRetry()).toBe(true);

      entity.retryCount = DEFAULT_MAX_RETRY_COUNT - 1;
      expect(entity.shouldRetry()).toBe(true);
    });

    it('should return false when status is not error', () => {
      entity.status = 'active';
      entity.retryCount = 0;
      expect(entity.shouldRetry()).toBe(false);

      entity.status = 'inactive';
      entity.retryCount = 0;
      expect(entity.shouldRetry()).toBe(false);
    });

    it('should return false when retry count exceeds limit', () => {
      entity.status = 'error';
      entity.retryCount = DEFAULT_MAX_RETRY_COUNT;
      expect(entity.shouldRetry()).toBe(false);

      entity.retryCount = DEFAULT_MAX_RETRY_COUNT + 1;
      expect(entity.shouldRetry()).toBe(false);
    });

    it('should respect custom max retry count parameter', () => {
      const customMaxRetry = 2;
      entity.status = 'error';
      entity.retryCount = 1;
      expect(entity.shouldRetry(customMaxRetry)).toBe(true);

      entity.retryCount = 2;
      expect(entity.shouldRetry(customMaxRetry)).toBe(false);
    });
  });

  describe('updateVerificationTime()', () => {
    it('should update lastVerifiedAt and updatedAt to current time', () => {
      const beforeUpdate = new Date();
      entity.lastVerifiedAt = new Date('2020-01-01');
      entity.updatedAt = new Date('2020-01-01');

      entity.updateVerificationTime();

      expect(entity.lastVerifiedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('updateSyncTime()', () => {
    it('should update lastSyncedAt and updatedAt to current time', () => {
      const beforeUpdate = new Date();
      entity.lastSyncedAt = new Date('2020-01-01');
      entity.updatedAt = new Date('2020-01-01');

      entity.updateSyncTime();

      expect(entity.lastSyncedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('setError()', () => {
    it('should set status to error and update error message and retry count', () => {
      const errorMessage = 'Test error message';
      entity.status = 'active';
      entity.errorMessage = null;
      entity.retryCount = 0;

      entity.setError(errorMessage);

      expect(entity.status).toBe('error');
      expect(entity.errorMessage).toBe(errorMessage);
      expect(entity.retryCount).toBe(1);
    });

    it('should increment retry count on subsequent errors', () => {
      entity.status = 'error';
      entity.retryCount = 2;

      entity.setError('Another error');

      expect(entity.retryCount).toBe(3);
    });

    it('should update updatedAt timestamp', () => {
      const beforeUpdate = new Date();
      entity.updatedAt = new Date('2020-01-01');

      entity.setError('Test error');

      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('clearError()', () => {
    it('should clear error status and message when status is error', () => {
      entity.status = 'error';
      entity.errorMessage = 'Some error';

      entity.clearError();

      expect(entity.status).toBe('active');
      expect(entity.errorMessage).toBeNull();
    });

    it('should not change status when not in error state', () => {
      entity.status = 'inactive';
      entity.errorMessage = null;

      entity.clearError();

      expect(entity.status).toBe('inactive');
      expect(entity.errorMessage).toBeNull();
    });

    it('should update updatedAt timestamp when clearing error', () => {
      const beforeUpdate = new Date();
      entity.status = 'error';
      entity.updatedAt = new Date('2020-01-01');

      entity.clearError();

      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('resetRetryCount()', () => {
    it('should reset retry count to zero', () => {
      entity.retryCount = 5;

      entity.resetRetryCount();

      expect(entity.retryCount).toBe(0);
    });

    it('should update updatedAt timestamp', () => {
      const beforeUpdate = new Date();
      entity.updatedAt = new Date('2020-01-01');

      entity.resetRetryCount();

      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('activate()', () => {
    it('should set status to active and clear error message and retry count', () => {
      entity.status = 'error';
      entity.errorMessage = 'Some error';
      entity.retryCount = 3;

      entity.activate();

      expect(entity.status).toBe('active');
      expect(entity.errorMessage).toBeNull();
      expect(entity.retryCount).toBe(0);
    });

    it('should update updatedAt timestamp', () => {
      const beforeUpdate = new Date();
      entity.updatedAt = new Date('2020-01-01');

      entity.activate();

      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('suspend()', () => {
    it('should set status to suspended', () => {
      entity.status = 'active';

      entity.suspend();

      expect(entity.status).toBe('suspended');
    });

    it('should set error message when reason is provided', () => {
      const reason = 'Suspended for maintenance';
      entity.errorMessage = null;

      entity.suspend(reason);

      expect(entity.errorMessage).toBe(reason);
    });

    it('should not change error message when no reason is provided', () => {
      const existingMessage = 'Existing message';
      entity.errorMessage = existingMessage;

      entity.suspend();

      expect(entity.errorMessage).toBe(existingMessage);
    });

    it('should update updatedAt timestamp', () => {
      const beforeUpdate = new Date();
      entity.updatedAt = new Date('2020-01-01');

      entity.suspend();

      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('deactivate()', () => {
    it('should set status to inactive', () => {
      entity.status = 'active';

      entity.deactivate();

      expect(entity.status).toBe('inactive');
    });

    it('should update updatedAt timestamp', () => {
      const beforeUpdate = new Date();
      entity.updatedAt = new Date('2020-01-01');

      entity.deactivate();

      expect(entity.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
    });
  });

  describe('edge cases and boundary conditions', () => {
    it('should handle null dates gracefully in time-based methods', () => {
      entity.lastVerifiedAt = null;
      entity.updatedAt = null as any; // 强制设置为null进行边界测试

      expect(() => entity.needsVerification()).not.toThrow();
      expect(entity.needsVerification()).toBe(true);
    });

    it('should handle zero retry count correctly', () => {
      entity.retryCount = 0;
      entity.status = 'error';

      expect(entity.shouldRetry()).toBe(true);
      expect(entity.isHealthy()).toBe(false);
    });

    it('should handle maximum retry count boundary', () => {
      entity.retryCount = DEFAULT_MAX_RETRY_COUNT;
      entity.status = 'error';

      expect(entity.shouldRetry()).toBe(false);
      expect(entity.isHealthy()).toBe(false);
    });

    it('should handle very large retry counts', () => {
      entity.retryCount = 999999;
      entity.status = 'active';

      expect(entity.isHealthy()).toBe(false);
      expect(entity.canBeDeleted()).toBe(true);
    });
  });
});