/**
 * API响应格式一致性属性测试
 * 
 * Property 7: API响应格式一致性
 * Validates: Requirements 4.1, 4.2, 4.3
 * 
 * 测试目标：
 * - 验证所有API端点返回统一的响应格式
 * - 确保成功和失败响应都符合规范
 * - 验证响应字段类型和必需性
 * 
 * 最近修改：
 * - 2026-01-08: 注释规范优化 - 修正@author字段，更新版本号和修改记录 (修改者: moyin)
 * - 2026-01-08: 功能新增 - 创建API响应格式属性测试 (修改者: assistant)
 * 
 * @author moyin
 * @version 1.0.1
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AdminDatabaseController } from '../../controllers/admin_database.controller';
import { DatabaseManagementService } from '../../services/database_management.service';
import { AdminOperationLogService } from '../../services/admin_operation_log.service';
import { AdminOperationLogInterceptor } from '../../admin_operation_log.interceptor';
import { AdminDatabaseExceptionFilter } from '../../admin_database_exception.filter';
import { AdminGuard } from '../../admin.guard';
import { UserStatus } from '../../../../core/db/users/user_status.enum';
import {
  PropertyTestRunner,
  PropertyTestGenerators,
  PropertyTestAssertions,
  DEFAULT_PROPERTY_CONFIG
} from './admin_property_test.base';

describe('Property Test: API响应格式一致性', () => {
  let app: INestApplication;
  let module: TestingModule;
  let controller: AdminDatabaseController;

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: ['.env.test', '.env']
        })
      ],
      controllers: [AdminDatabaseController],
      providers: [
        DatabaseManagementService,
        {
          provide: AdminOperationLogService,
          useValue: {
            createLog: jest.fn().mockResolvedValue({}),
            queryLogs: jest.fn().mockResolvedValue({ logs: [], total: 0 }),
            getLogById: jest.fn().mockResolvedValue(null),
            getStatistics: jest.fn().mockResolvedValue({}),
            cleanupExpiredLogs: jest.fn().mockResolvedValue(0),
            getAdminOperationHistory: jest.fn().mockResolvedValue([]),
            getSensitiveOperations: jest.fn().mockResolvedValue({ logs: [], total: 0 })
          }
        },
        {
          provide: AdminOperationLogInterceptor,
          useValue: {
            intercept: jest.fn().mockImplementation((context, next) => next.handle())
          }
        },
        {
          provide: 'UsersService',
          useValue: {
            findAll: jest.fn().mockResolvedValue([]),
            findOne: jest.fn().mockImplementation(() => {
              const user = PropertyTestGenerators.generateUser();
              return Promise.resolve({ ...user, id: BigInt(1) });
            }),
            create: jest.fn().mockImplementation((userData) => {
              return Promise.resolve({ ...userData, id: BigInt(1) });
            }),
            update: jest.fn().mockImplementation((id, updateData) => {
              const user = PropertyTestGenerators.generateUser();
              return Promise.resolve({ ...user, ...updateData, id });
            }),
            remove: jest.fn().mockResolvedValue(undefined),
            search: jest.fn().mockResolvedValue([]),
            count: jest.fn().mockResolvedValue(0)
          }
        },
        {
          provide: 'IUserProfilesService',
          useValue: {
            findAll: jest.fn().mockResolvedValue([]),
            findOne: jest.fn().mockImplementation(() => {
              const profile = PropertyTestGenerators.generateUserProfile();
              return Promise.resolve({ ...profile, id: BigInt(1) });
            }),
            create: jest.fn().mockImplementation((profileData) => {
              return Promise.resolve({ ...profileData, id: BigInt(1) });
            }),
            update: jest.fn().mockImplementation((id, updateData) => {
              const profile = PropertyTestGenerators.generateUserProfile();
              return Promise.resolve({ ...profile, ...updateData, id });
            }),
            remove: jest.fn().mockResolvedValue(undefined),
            findByMap: jest.fn().mockResolvedValue([]),
            count: jest.fn().mockResolvedValue(0)
          }
        },
        {
          provide: 'ZulipAccountsService',
          useValue: {
            findMany: jest.fn().mockResolvedValue({ accounts: [] }),
            findById: jest.fn().mockImplementation(() => {
              const account = PropertyTestGenerators.generateZulipAccount();
              return Promise.resolve({ ...account, id: '1' });
            }),
            create: jest.fn().mockImplementation((accountData) => {
              return Promise.resolve({ ...accountData, id: '1' });
            }),
            update: jest.fn().mockImplementation((id, updateData) => {
              const account = PropertyTestGenerators.generateZulipAccount();
              return Promise.resolve({ ...account, ...updateData, id });
            }),
            delete: jest.fn().mockResolvedValue(undefined),
            getStatusStatistics: jest.fn().mockResolvedValue({
              active: 0,
              inactive: 0,
              suspended: 0,
              error: 0,
              total: 0
            })
          }
        }
      ]
    })
    .overrideGuard(AdminGuard)
    .useValue({ canActivate: () => true })
    .compile();

    app = module.createNestApplication();
    app.useGlobalFilters(new AdminDatabaseExceptionFilter());
    await app.init();

    controller = module.get<AdminDatabaseController>(AdminDatabaseController);
  });

  afterAll(async () => {
    await app.close();
  });

  describe('Property 7: API响应格式一致性', () => {
    it('所有成功响应应该有统一的格式', async () => {
      await PropertyTestRunner.runPropertyTest(
        'API成功响应格式一致性',
        () => PropertyTestGenerators.generateUser(),
        async (userData) => {
          // 测试用户管理端点
          const userListResponse = await controller.getUserList(20, 0);
          PropertyTestAssertions.assertListResponseFormat(userListResponse);

          const userDetailResponse = await controller.getUserById('1');
          PropertyTestAssertions.assertApiResponseFormat(userDetailResponse, true);

          const createUserResponse = await controller.createUser({
            ...userData,
            status: UserStatus.ACTIVE
          });
          PropertyTestAssertions.assertApiResponseFormat(createUserResponse, true);

          // 测试用户档案管理端点
          const profileListResponse = await controller.getUserProfileList(20, 0);
          PropertyTestAssertions.assertListResponseFormat(profileListResponse);

          const profileDetailResponse = await controller.getUserProfileById('1');
          PropertyTestAssertions.assertApiResponseFormat(profileDetailResponse, true);

          // 测试Zulip账号管理端点
          const zulipListResponse = await controller.getZulipAccountList(20, 0);
          PropertyTestAssertions.assertListResponseFormat(zulipListResponse);

          const zulipDetailResponse = await controller.getZulipAccountById('1');
          PropertyTestAssertions.assertApiResponseFormat(zulipDetailResponse, true);

          const zulipStatsResponse = await controller.getZulipAccountStatistics();
          PropertyTestAssertions.assertApiResponseFormat(zulipStatsResponse, true);

          // 测试系统端点
          const healthResponse = await controller.healthCheck();
          PropertyTestAssertions.assertApiResponseFormat(healthResponse, true);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 50 }
      );
    });

    it('所有列表响应应该有正确的分页信息', async () => {
      await PropertyTestRunner.runPropertyTest(
        '列表响应分页格式一致性',
        () => PropertyTestGenerators.generatePaginationParams(),
        async (paginationParams) => {
          const { limit, offset } = paginationParams;
          
          // 限制参数范围以避免无效请求
          const safeLimit = Math.min(Math.max(limit, 1), 100);
          const safeOffset = Math.max(offset, 0);

          // 测试所有列表端点
          const userListResponse = await controller.getUserList(safeLimit, safeOffset);
          PropertyTestAssertions.assertPaginationLogic(userListResponse, safeLimit, safeOffset);

          const profileListResponse = await controller.getUserProfileList(safeLimit, safeOffset);
          PropertyTestAssertions.assertPaginationLogic(profileListResponse, safeLimit, safeOffset);

          const zulipListResponse = await controller.getZulipAccountList(safeLimit, safeOffset);
          PropertyTestAssertions.assertPaginationLogic(zulipListResponse, safeLimit, safeOffset);

          const mapProfilesResponse = await controller.getUserProfilesByMap('plaza', safeLimit, safeOffset);
          PropertyTestAssertions.assertPaginationLogic(mapProfilesResponse, safeLimit, safeOffset);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 30 }
      );
    });

    it('响应时间戳应该是有效的ISO格式', async () => {
      await PropertyTestRunner.runPropertyTest(
        '响应时间戳格式验证',
        () => ({}),
        async () => {
          const response = await controller.healthCheck();
          
          expect(response.timestamp).toBeDefined();
          expect(typeof response.timestamp).toBe('string');
          
          // 验证ISO 8601格式
          const timestamp = new Date(response.timestamp);
          expect(timestamp.toISOString()).toBe(response.timestamp);
          
          // 验证时间戳是最近的（在过去1分钟内）
          const now = new Date();
          const timeDiff = now.getTime() - timestamp.getTime();
          expect(timeDiff).toBeLessThan(60000); // 1分钟
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 20 }
      );
    });

    it('请求ID应该是唯一的', async () => {
      const requestIds = new Set<string>();
      
      await PropertyTestRunner.runPropertyTest(
        '请求ID唯一性验证',
        () => ({}),
        async () => {
          const response = await controller.healthCheck();
          
          expect(response.request_id).toBeDefined();
          expect(typeof response.request_id).toBe('string');
          expect(response.request_id.length).toBeGreaterThan(0);
          
          // 验证请求ID唯一性
          expect(requestIds.has(response.request_id)).toBe(false);
          requestIds.add(response.request_id);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 100 }
      );
    });
  });
});