/**
 * 用户档案管理属性测试
 * 
 * Property 3: 用户档案管理操作完整性
 * Property 4: 地图用户查询正确性
 * 
 * Validates: Requirements 2.1-2.6
 * 
 * 测试目标：
 * - 验证用户档案CRUD操作的完整性
 * - 确保地图查询功能的正确性
 * - 验证位置数据的处理逻辑
 * 
 * 最近修改：
 * - 2026-01-08: 注释规范优化 - 修正@author字段，更新版本号和修改记录 (修改者: moyin)
 * - 2026-01-08: 功能新增 - 创建用户档案管理属性测试 (修改者: 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 './admin_database.controller';
import { DatabaseManagementService } from './database_management.service';
import { AdminOperationLogService } from './admin_operation_log.service';
import { AdminOperationLogInterceptor } from './admin_operation_log.interceptor';
import { AdminDatabaseExceptionFilter } from './admin_database_exception.filter';
import { AdminGuard } from './admin.guard';
import {
  PropertyTestRunner,
  PropertyTestGenerators,
  PropertyTestAssertions,
  DEFAULT_PROPERTY_CONFIG
} from './admin_property_test.base';

describe('Property Test: 用户档案管理功能', () => {
  let app: INestApplication;
  let module: TestingModule;
  let controller: AdminDatabaseController;
  let mockUserProfilesService: any;

  beforeAll(async () => {
    mockUserProfilesService = {
      findAll: jest.fn().mockResolvedValue([]),
      findOne: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
      remove: jest.fn().mockResolvedValue(undefined),
      findByMap: jest.fn(),
      count: jest.fn().mockResolvedValue(0)
    };

    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().mockResolvedValue({ id: BigInt(1) }),
            create: jest.fn().mockResolvedValue({ id: BigInt(1) }),
            update: jest.fn().mockResolvedValue({ id: BigInt(1) }),
            remove: jest.fn().mockResolvedValue(undefined),
            search: jest.fn().mockResolvedValue([]),
            count: jest.fn().mockResolvedValue(0)
          }
        },
        {
          provide: 'IUserProfilesService',
          useValue: mockUserProfilesService
        },
        {
          provide: 'ZulipAccountsService',
          useValue: {
            findMany: jest.fn().mockResolvedValue({ accounts: [] }),
            findById: jest.fn().mockResolvedValue({ id: '1' }),
            create: jest.fn().mockResolvedValue({ id: '1' }),
            update: jest.fn().mockResolvedValue({ id: '1' }),
            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 3: 用户档案管理操作完整性', () => {
    it('创建用户档案后应该能够读取相同的数据', async () => {
      await PropertyTestRunner.runPropertyTest(
        '用户档案创建-读取一致性',
        () => PropertyTestGenerators.generateUserProfile(),
        async (profileData) => {
          const profileWithId = { ...profileData, id: BigInt(1) };
          
          // Mock创建和读取操作
          mockUserProfilesService.create.mockResolvedValueOnce(profileWithId);
          mockUserProfilesService.findOne.mockResolvedValueOnce(profileWithId);

          // 执行创建操作
          const createResponse = await controller.createUserProfile(profileData);
          
          // 执行读取操作
          const readResponse = await controller.getUserProfileById('1');

          // 验证一致性
          PropertyTestAssertions.assertCrudConsistency(
            createResponse,
            readResponse,
            createResponse
          );

          expect(createResponse.data.user_id).toBe(profileData.user_id);
          expect(readResponse.data.user_id).toBe(profileData.user_id);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 30 }
      );
    });

    it('更新用户档案后数据应该反映变更', async () => {
      await PropertyTestRunner.runPropertyTest(
        '用户档案更新一致性',
        () => ({
          original: PropertyTestGenerators.generateUserProfile(),
          updates: PropertyTestGenerators.generateUserProfile()
        }),
        async ({ original, updates }) => {
          const originalWithId = { ...original, id: BigInt(1) };
          const updatedProfile = { ...originalWithId, ...updates };
          
          // Mock操作
          mockUserProfilesService.findOne.mockResolvedValueOnce(originalWithId);
          mockUserProfilesService.update.mockResolvedValueOnce(updatedProfile);

          // 执行更新操作
          const updateResponse = await controller.updateUserProfile('1', updates);

          expect(updateResponse.success).toBe(true);
          expect(updateResponse.data.id).toBe('1');
          
          // 验证更新的字段
          if (updates.bio) {
            expect(updateResponse.data.bio).toBe(updates.bio);
          }
          if (updates.current_map) {
            expect(updateResponse.data.current_map).toBe(updates.current_map);
          }
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 30 }
      );
    });

    it('位置数据应该被正确处理', async () => {
      await PropertyTestRunner.runPropertyTest(
        '位置数据处理正确性',
        () => {
          const profile = PropertyTestGenerators.generateUserProfile();
          return {
            ...profile,
            pos_x: Math.random() * 2000 - 1000, // -1000 到 1000
            pos_y: Math.random() * 2000 - 1000, // -1000 到 1000
          };
        },
        async (profileData) => {
          const profileWithId = { ...profileData, id: BigInt(1) };
          
          mockUserProfilesService.create.mockResolvedValueOnce(profileWithId);

          const createResponse = await controller.createUserProfile(profileData);

          expect(createResponse.success).toBe(true);
          expect(typeof createResponse.data.pos_x).toBe('number');
          expect(typeof createResponse.data.pos_y).toBe('number');
          
          // 验证位置数据的合理性
          expect(createResponse.data.pos_x).toBe(profileData.pos_x);
          expect(createResponse.data.pos_y).toBe(profileData.pos_y);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 25 }
      );
    });

    it('JSON字段应该被正确序列化和反序列化', async () => {
      await PropertyTestRunner.runPropertyTest(
        'JSON字段处理正确性',
        () => {
          const profile = PropertyTestGenerators.generateUserProfile();
          return {
            ...profile,
            tags: JSON.stringify(['tag1', 'tag2', 'tag3']),
            social_links: JSON.stringify({
              github: 'https://github.com/user',
              linkedin: 'https://linkedin.com/in/user',
              twitter: 'https://twitter.com/user'
            })
          };
        },
        async (profileData) => {
          const profileWithId = { ...profileData, id: BigInt(1) };
          
          mockUserProfilesService.create.mockResolvedValueOnce(profileWithId);

          const createResponse = await controller.createUserProfile(profileData);

          expect(createResponse.success).toBe(true);
          expect(createResponse.data.tags).toBe(profileData.tags);
          expect(createResponse.data.social_links).toBe(profileData.social_links);
          
          // 验证JSON格式有效性
          expect(() => JSON.parse(profileData.tags)).not.toThrow();
          expect(() => JSON.parse(profileData.social_links)).not.toThrow();
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 20 }
      );
    });
  });

  describe('Property 4: 地图用户查询正确性', () => {
    it('按地图查询应该返回正确的用户档案', async () => {
      await PropertyTestRunner.runPropertyTest(
        '地图查询正确性',
        () => {
          const maps = ['plaza', 'forest', 'beach', 'mountain', 'city'];
          const selectedMap = maps[Math.floor(Math.random() * maps.length)];
          const profiles = Array.from({ length: 5 }, () => {
            const profile = PropertyTestGenerators.generateUserProfile();
            return {
              ...profile,
              id: BigInt(Math.floor(Math.random() * 1000) + 1),
              current_map: Math.random() > 0.5 ? selectedMap : maps[Math.floor(Math.random() * maps.length)]
            };
          });
          
          return { selectedMap, profiles };
        },
        async ({ selectedMap, profiles }) => {
          // 过滤出应该匹配的档案
          const expectedProfiles = profiles.filter(p => p.current_map === selectedMap);
          
          mockUserProfilesService.findByMap.mockResolvedValueOnce(expectedProfiles);
          mockUserProfilesService.count.mockResolvedValueOnce(expectedProfiles.length);

          const response = await controller.getUserProfilesByMap(selectedMap, 20, 0);

          expect(response.success).toBe(true);
          PropertyTestAssertions.assertListResponseFormat(response);
          
          // 验证返回的档案都属于指定地图
          response.data.items.forEach((profile: any) => {
            expect(profile.current_map).toBe(selectedMap);
          });
          
          expect(response.data.items.length).toBe(expectedProfiles.length);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 25 }
      );
    });

    it('不存在的地图应该返回空结果', async () => {
      await PropertyTestRunner.runPropertyTest(
        '不存在地图查询处理',
        () => ({
          nonExistentMap: `nonexistent_${Math.random().toString(36).substring(7)}`
        }),
        async ({ nonExistentMap }) => {
          mockUserProfilesService.findByMap.mockResolvedValueOnce([]);
          mockUserProfilesService.count.mockResolvedValueOnce(0);

          const response = await controller.getUserProfilesByMap(nonExistentMap, 20, 0);

          expect(response.success).toBe(true);
          expect(response.data.items).toEqual([]);
          expect(response.data.total).toBe(0);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 15 }
      );
    });

    it('地图查询应该支持分页', async () => {
      await PropertyTestRunner.runPropertyTest(
        '地图查询分页支持',
        () => {
          const map = 'plaza';
          const pagination = PropertyTestGenerators.generatePaginationParams();
          const totalProfiles = Math.floor(Math.random() * 100) + 50; // 50-149个档案
          
          return { map, pagination, totalProfiles };
        },
        async ({ map, pagination, totalProfiles }) => {
          const { limit, offset } = pagination;
          const safeLimit = Math.min(Math.max(limit, 1), 100);
          const safeOffset = Math.max(offset, 0);
          
          // 模拟分页结果
          const itemsToReturn = Math.min(safeLimit, Math.max(0, totalProfiles - safeOffset));
          const mockProfiles = Array.from({ length: itemsToReturn }, (_, i) => ({
            ...PropertyTestGenerators.generateUserProfile(),
            id: BigInt(safeOffset + i + 1),
            current_map: map
          }));
          
          mockUserProfilesService.findByMap.mockResolvedValueOnce(mockProfiles);
          mockUserProfilesService.count.mockResolvedValueOnce(totalProfiles);

          const response = await controller.getUserProfilesByMap(map, safeLimit, safeOffset);

          expect(response.success).toBe(true);
          PropertyTestAssertions.assertPaginationLogic(response, safeLimit, safeOffset);
          
          // 验证返回的档案数量
          expect(response.data.items.length).toBe(itemsToReturn);
          expect(response.data.total).toBe(totalProfiles);
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 20 }
      );
    });

    it('地图名称应该被正确处理', async () => {
      await PropertyTestRunner.runPropertyTest(
        '地图名称处理',
        () => {
          const mapNames = [
            'plaza', 'forest', 'beach', 'mountain', 'city',
            'special-map', 'map_with_underscore', 'map123',
            '中文地图', 'café-map'
          ];
          return {
            mapName: mapNames[Math.floor(Math.random() * mapNames.length)]
          };
        },
        async ({ mapName }) => {
          mockUserProfilesService.findByMap.mockResolvedValueOnce([]);
          mockUserProfilesService.count.mockResolvedValueOnce(0);

          const response = await controller.getUserProfilesByMap(mapName, 20, 0);

          expect(response.success).toBe(true);
          expect(response.data).toBeDefined();
          
          // 验证地图名称被正确传递
          expect(mockUserProfilesService.findByMap).toHaveBeenCalledWith(
            mapName, undefined, 20, 0
          );
        },
        { ...DEFAULT_PROPERTY_CONFIG, iterations: 15 }
      );
    });
  });
});