/**
 * Zulip账号关联数据访问服务基类测试
 * 
 * 功能描述：
 * - 测试基类的通用工具方法
 * - 验证错误处理和日志记录功能
 * - 测试性能监控和数据转换方法
 * - 确保基类功能的正确性和健壮性
 * 
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 创建缺失的测试文件，确保测试覆盖完整性 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.0.0
 * @since 2026-01-12
 * @lastModified 2026-01-12
 */

import { Test, TestingModule } from '@nestjs/testing';
import { BaseZulipAccountsService } from './base_zulip_accounts.service';
import { AppLoggerService } from '../../utils/logger/logger.service';

// 创建具体的测试类来测试抽象基类
class TestZulipAccountsService extends BaseZulipAccountsService {
  constructor(logger: AppLoggerService) {
    super(logger, 'TestZulipAccountsService');
  }

  // 实现抽象方法
  protected toResponseDto(entity: any): any {
    return {
      id: entity.id?.toString(),
      gameUserId: entity.gameUserId?.toString(),
      zulipUserId: entity.zulipUserId,
      zulipEmail: entity.zulipEmail,
    };
  }

  // 暴露受保护的方法用于测试
  public testFormatError(error: unknown): string {
    return this.formatError(error);
  }

  public testHandleDataAccessError(error: unknown, operation: string, context?: Record<string, any>): never {
    return this.handleDataAccessError(error, operation, context);
  }

  public testHandleSearchError(error: unknown, operation: string, context?: Record<string, any>): any[] {
    return this.handleSearchError(error, operation, context);
  }

  public testLogSuccess(operation: string, context?: Record<string, any>, duration?: number): void {
    return this.logSuccess(operation, context, duration);
  }

  public testLogStart(operation: string, context?: Record<string, any>): void {
    return this.logStart(operation, context);
  }

  public testCreatePerformanceMonitor(operation: string, context?: Record<string, any>) {
    return this.createPerformanceMonitor(operation, context);
  }

  public testParseGameUserId(gameUserId: string): bigint {
    return this.parseGameUserId(gameUserId);
  }

  public testParseIds(ids: string[]): bigint[] {
    return this.parseIds(ids);
  }

  public testParseId(id: string): bigint {
    return this.parseId(id);
  }

  public testToResponseDtoArray(entities: any[]): any[] {
    return this.toResponseDtoArray(entities);
  }

  public testBuildListResponse(entities: any[]): any {
    return this.buildListResponse(entities);
  }
}

describe('BaseZulipAccountsService', () => {
  let service: TestZulipAccountsService;
  let logger: jest.Mocked<AppLoggerService>;

  beforeEach(async () => {
    const mockLogger = {
      info: jest.fn(),
      debug: jest.fn(),
      warn: jest.fn(),
      error: jest.fn(),
    };

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        {
          provide: AppLoggerService,
          useValue: mockLogger,
        },
      ],
    }).compile();

    logger = module.get(AppLoggerService);
    service = new TestZulipAccountsService(logger);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('formatError', () => {
    it('should format Error objects correctly', () => {
      const error = new Error('Test error message');
      const result = service.testFormatError(error);
      expect(result).toBe('Test error message');
    });

    it('should format string errors correctly', () => {
      const result = service.testFormatError('String error');
      expect(result).toBe('String error');
    });

    it('should format number errors correctly', () => {
      const result = service.testFormatError(404);
      expect(result).toBe('404');
    });

    it('should format object errors correctly', () => {
      const result = service.testFormatError({ message: 'Object error' });
      expect(result).toBe('[object Object]');
    });

    it('should format null and undefined correctly', () => {
      expect(service.testFormatError(null)).toBe('null');
      expect(service.testFormatError(undefined)).toBe('undefined');
    });
  });

  describe('handleDataAccessError', () => {
    it('should log error and rethrow', () => {
      const error = new Error('Database error');
      const operation = 'test operation';
      const context = { userId: '123' };

      expect(() => {
        service.testHandleDataAccessError(error, operation, context);
      }).toThrow(error);

      expect(logger.error).toHaveBeenCalledWith(
        'test operation失败',
        expect.objectContaining({
          module: 'TestZulipAccountsService',
          operation: 'test operation',
          error: 'Database error',
          context: { userId: '123' },
          timestamp: expect.any(String),
        }),
        expect.any(String)
      );
    });

    it('should handle non-Error objects', () => {
      const error = 'String error';
      const operation = 'test operation';

      expect(() => {
        service.testHandleDataAccessError(error, operation);
      }).toThrow(error);

      expect(logger.error).toHaveBeenCalledWith(
        'test operation失败',
        expect.objectContaining({
          error: 'String error',
        }),
        undefined
      );
    });
  });

  describe('handleSearchError', () => {
    it('should log warning and return empty array', () => {
      const error = new Error('Search error');
      const operation = 'search operation';
      const context = { query: 'test' };

      const result = service.testHandleSearchError(error, operation, context);

      expect(result).toEqual([]);
      expect(logger.warn).toHaveBeenCalledWith(
        'search operation失败，返回空结果',
        expect.objectContaining({
          module: 'TestZulipAccountsService',
          operation: 'search operation',
          error: 'Search error',
          context: { query: 'test' },
          timestamp: expect.any(String),
        })
      );
    });
  });

  describe('logSuccess', () => {
    it('should log success message', () => {
      const operation = 'test operation';
      const context = { result: 'success' };
      const duration = 100;

      service.testLogSuccess(operation, context, duration);

      expect(logger.info).toHaveBeenCalledWith(
        'test operation成功',
        expect.objectContaining({
          module: 'TestZulipAccountsService',
          operation: 'test operation',
          context: { result: 'success' },
          duration: 100,
          timestamp: expect.any(String),
        })
      );
    });

    it('should log success without context and duration', () => {
      service.testLogSuccess('simple operation');

      expect(logger.info).toHaveBeenCalledWith(
        'simple operation成功',
        expect.objectContaining({
          module: 'TestZulipAccountsService',
          operation: 'simple operation',
        })
      );
    });
  });

  describe('logStart', () => {
    it('should log start message', () => {
      const operation = 'test operation';
      const context = { input: 'data' };

      service.testLogStart(operation, context);

      expect(logger.info).toHaveBeenCalledWith(
        '开始test operation',
        expect.objectContaining({
          module: 'TestZulipAccountsService',
          operation: 'test operation',
          context: { input: 'data' },
          timestamp: expect.any(String),
        })
      );
    });
  });

  describe('createPerformanceMonitor', () => {
    it('should create performance monitor with success callback', () => {
      const monitor = service.testCreatePerformanceMonitor('test operation', { test: 'context' });

      expect(monitor).toHaveProperty('success');
      expect(monitor).toHaveProperty('error');
      expect(typeof monitor.success).toBe('function');
      expect(typeof monitor.error).toBe('function');

      // 测试成功回调
      monitor.success({ result: 'completed' });

      expect(logger.info).toHaveBeenCalledWith(
        '开始test operation',
        expect.objectContaining({
          operation: 'test operation',
          context: { test: 'context' },
        })
      );

      expect(logger.info).toHaveBeenCalledWith(
        'test operation成功',
        expect.objectContaining({
          duration: expect.any(Number),
        })
      );
    });

    it('should create performance monitor with error callback', () => {
      const monitor = service.testCreatePerformanceMonitor('test operation');
      const error = new Error('Test error');

      expect(() => monitor.error(error)).toThrow(error);
      expect(logger.error).toHaveBeenCalled();
    });
  });

  describe('parseGameUserId', () => {
    it('should parse valid game user ID', () => {
      const result = service.testParseGameUserId('12345');
      expect(result).toBe(BigInt(12345));
    });

    it('should parse large game user ID', () => {
      const result = service.testParseGameUserId('9007199254740991');
      expect(result).toBe(BigInt('9007199254740991'));
    });

    it('should throw error for invalid game user ID', () => {
      expect(() => service.testParseGameUserId('invalid')).toThrow('无效的游戏用户ID格式: invalid');
    });

    it('should handle empty string as valid BigInt(0)', () => {
      const result = service.testParseGameUserId('');
      expect(result).toBe(BigInt(0));
    });
  });

  describe('parseIds', () => {
    it('should parse valid ID array', () => {
      const result = service.testParseIds(['1', '2', '3']);
      expect(result).toEqual([BigInt(1), BigInt(2), BigInt(3)]);
    });

    it('should parse empty array', () => {
      const result = service.testParseIds([]);
      expect(result).toEqual([]);
    });

    it('should throw error for invalid ID in array', () => {
      expect(() => service.testParseIds(['1', 'invalid', '3'])).toThrow('无效的ID格式: 1, invalid, 3');
    });
  });

  describe('parseId', () => {
    it('should parse valid ID', () => {
      const result = service.testParseId('123');
      expect(result).toBe(BigInt(123));
    });

    it('should throw error for invalid ID', () => {
      expect(() => service.testParseId('invalid')).toThrow('无效的ID格式: invalid');
    });
  });

  describe('toResponseDtoArray', () => {
    it('should convert entity array to DTO array', () => {
      const entities = [
        { id: BigInt(1), gameUserId: BigInt(123), zulipUserId: 456, zulipEmail: 'test1@example.com' },
        { id: BigInt(2), gameUserId: BigInt(124), zulipUserId: 457, zulipEmail: 'test2@example.com' },
      ];

      const result = service.testToResponseDtoArray(entities);

      expect(result).toHaveLength(2);
      expect(result[0]).toEqual({
        id: '1',
        gameUserId: '123',
        zulipUserId: 456,
        zulipEmail: 'test1@example.com',
      });
      expect(result[1]).toEqual({
        id: '2',
        gameUserId: '124',
        zulipUserId: 457,
        zulipEmail: 'test2@example.com',
      });
    });

    it('should handle empty array', () => {
      const result = service.testToResponseDtoArray([]);
      expect(result).toEqual([]);
    });
  });

  describe('buildListResponse', () => {
    it('should build list response object', () => {
      const entities = [
        { id: BigInt(1), gameUserId: BigInt(123), zulipUserId: 456, zulipEmail: 'test1@example.com' },
        { id: BigInt(2), gameUserId: BigInt(124), zulipUserId: 457, zulipEmail: 'test2@example.com' },
      ];

      const result = service.testBuildListResponse(entities);

      expect(result).toEqual({
        accounts: [
          {
            id: '1',
            gameUserId: '123',
            zulipUserId: 456,
            zulipEmail: 'test1@example.com',
          },
          {
            id: '2',
            gameUserId: '124',
            zulipUserId: 457,
            zulipEmail: 'test2@example.com',
          },
        ],
        total: 2,
        count: 2,
      });
    });

    it('should handle empty entity list', () => {
      const result = service.testBuildListResponse([]);

      expect(result).toEqual({
        accounts: [],
        total: 0,
        count: 0,
      });
    });
  });

  describe('constructor', () => {
    it('should initialize with default module name', () => {
      const defaultService = new TestZulipAccountsService(logger);
      expect(defaultService).toBeDefined();
    });

    it('should initialize with custom module name', () => {
      class CustomTestService extends BaseZulipAccountsService {
        constructor(logger: AppLoggerService) {
          super(logger, 'CustomTestService');
        }
        protected toResponseDto(entity: any): any {
          return entity;
        }
      }

      const customService = new CustomTestService(logger);
      expect(customService).toBeDefined();
    });
  });
});