import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { PrismaService } from '@/core/database/prisma/prisma.service';
import { createTestApp } from '../../helpers/app.helper';
import { cleanupDatabase } from '../../helpers/cleanup.helper';
import { createAdminUser, createTestUser } from '../../helpers/factories/user.factory';

/**
 * Meeting-attendance · Cities Controller L1 集成测试
 *
 * 覆盖 1 个 endpoint × HTTP 行为 + 鉴权 + 核心业务规则：
 *   GET /meeting-attendance/cities/suggestions
 *
 * 数据源：users.work_city + meetings.city + meeting_series.city
 * keyword 过滤（大小写不敏感）、limit 上限、去重
 *
 * 关联工单 #341 · Batch 1-A
 */
describe('Meeting-attendance · Cities API', () => {
  let app: INestApplication;
  let prisma: PrismaService;

  beforeAll(async () => {
    process.env.NODE_ENV = 'test';
    app = await createTestApp();
    prisma = app.get<PrismaService>(PrismaService);
  });

  afterEach(async () => {
    jest.restoreAllMocks();
    await cleanupDatabase(prisma);
  });

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

  // ============================================================
  // helpers
  // ============================================================

  function suffix() {
    return `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
  }

  async function login(username: string, password: string): Promise<string> {
    const resp = await request(app.getHttpServer())
      .post('/api/v1/auth/login')
      .send({ username, password })
      .expect(200);
    return resp.body.data.accessToken as string;
  }

  async function setupAdmin() {
    const s = suffix();
    const adminUser = await createAdminUser({
      username: `ci_cities_adm_${s}`,
      email: `ci_cities_adm_${s}@example.com`,
      password: 'Admin@123',
      displayName: `Cities Admin ${s}`,
    });
    const adminToken = await login(adminUser.username, 'Admin@123');
    return { adminUser, adminToken };
  }

  async function setupEmployee() {
    const s = suffix();
    const employee = await createTestUser({
      username: `ci_cities_emp_${s}`,
      email: `ci_cities_emp_${s}@example.com`,
      password: 'Emp@123',
      displayName: `Cities Emp ${s}`,
    });

    // ensure Employee role exists
    await prisma.role.upsert({
      where: { code: 'Employee' },
      create: { code: 'Employee', name: 'Employee', enabled: true, isBuiltIn: true },
      update: { enabled: true },
    });

    const empToken = await login(employee.username, 'Emp@123');
    return { employee, empToken };
  }

  // ============================================================
  // GET /meeting-attendance/cities/suggestions
  // ============================================================

  describe('GET /meeting-attendance/cities/suggestions', () => {
    it('[1] 鉴权：有效 token → 200 返回 { items: [...] }', async () => {
      const { adminToken } = await setupAdmin();

      const resp = await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/cities/suggestions')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body).toHaveProperty('items');
      expect(Array.isArray(resp.body.items)).toBe(true);
    });

    it('[2] 鉴权：无 Authorization 头 → 401', async () => {
      await request(app.getHttpServer())
        .get('/api/v1/meeting-attendance/cities/suggestions')
        .expect(401);
    });

    it('[3] keyword 过滤（大小写不敏感）：user.workCity 含关键字时出现在结果中', async () => {
      const { adminUser, adminToken } = await setupAdmin();

      const uniqueCity = `TestCityXYZ_${suffix()}`;
      // 直接更新 adminUser 的 workCity
      await (prisma as any).user.update({
        where: { id: adminUser.id },
        data: { workCity: uniqueCity },
      });

      // 用小写关键字查，期望匹配（大小写不敏感）
      const keyword = uniqueCity.slice(0, 12).toLowerCase();
      const resp = await request(app.getHttpServer())
        .get(`/api/v1/meeting-attendance/cities/suggestions?keyword=${keyword}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(resp.body.items).toContain(uniqueCity);
    });
  });
});
