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';

/**
 * v1.4 enforce-checkin-mode ON→OFF 数据联动集成测试
 *
 * 覆盖：
 *   1. Meeting-level ON→OFF 清空本场所有 MeetingRequiredAttendee.checkinMode
 *   2. Meeting-level OFF→ON 不动 checkinMode（无 clearedAttendeeOverrides 字段）
 *   3. Series-level ON→OFF 级联清空所有下属会议的 MeetingRequiredAttendee.checkinMode
 *   4. Series-level ON→OFF **保留** MeetingSeriesAttendeePreference（系列级默认覆盖）
 *   5. OFF→ON 后 listRequiredAttendees 能从保留的系列级覆盖派生 allowedMode
 */
describe('v1.4 enforce-checkin-mode toggle data sync', () => {
  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();
  });

  async function loginAsAdmin() {
    const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const adminUser = await createAdminUser({
      username: `v14_admin_${suffix}`,
      email: `v14_admin_${suffix}@example.com`,
      password: 'Admin@123',
      displayName: 'v1.4 Admin',
    });
    const resp = await request(app.getHttpServer())
      .post('/api/v1/auth/login')
      .send({ username: adminUser.username, password: 'Admin@123' })
      .expect(200);
    return { adminUser, adminToken: resp.body.data.accessToken as string };
  }

  async function createMeetingWithAttendees(opts: {
    creatorId: string;
    seriesId?: string | null;
    city?: string | null;
    enforceCheckinMode?: boolean;
    attendeeCheckinModes: Array<'ON_SITE' | 'ONLINE' | null>;
  }) {
    const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const meeting = await prisma.meeting.create({
      data: {
        title: `v1.4 Meeting ${suffix}`,
        startTime: new Date('2026-06-01T10:00:00Z'),
        endTime: new Date('2026-06-01T11:00:00Z'),
        timezone: 'UTC',
        location: 'HQ',
        type: 'HYBRID',
        status: 'SCHEDULED',
        creatorId: opts.creatorId,
        seriesId: opts.seriesId ?? null,
        city: opts.city ?? null,
        enforceCheckinMode: opts.enforceCheckinMode ?? true,
      } as any,
    });

    const users: Array<{ id: string; checkinMode: 'ON_SITE' | 'ONLINE' | null }> = [];
    for (let i = 0; i < opts.attendeeCheckinModes.length; i++) {
      const u = await createTestUser({
        username: `v14_user_${suffix}_${i}`,
        email: `v14_user_${suffix}_${i}@example.com`,
        displayName: `v1.4 User ${suffix}-${i}`,
      } as any);
      await prisma.meetingRequiredAttendee.create({
        data: {
          meetingId: meeting.id,
          userId: u.id,
          role: 'REGULAR_ATTENDEE',
          checkinMode: opts.attendeeCheckinModes[i],
        } as any,
      });
      users.push({ id: u.id, checkinMode: opts.attendeeCheckinModes[i] });
    }

    return { meeting, users };
  }

  it('[1] Meeting ON→OFF 清空本场所有 MeetingRequiredAttendee.checkinMode 并返回 clearedAttendeeOverrides', async () => {
    const { adminUser, adminToken } = await loginAsAdmin();
    const { meeting } = await createMeetingWithAttendees({
      creatorId: adminUser.id,
      city: 'Beijing',
      enforceCheckinMode: true,
      attendeeCheckinModes: ['ON_SITE', 'ONLINE', null], // 2 overrides + 1 已是 null
    });

    const resp = await request(app.getHttpServer())
      .patch(`/api/v1/meeting-attendance/meetings/${meeting.id}/enforce-checkin-mode`)
      .set('Authorization', `Bearer ${adminToken}`)
      .send({ enforceCheckinMode: false })
      .expect(200);

    expect(resp.body).toMatchObject({
      meetingId: meeting.id,
      enforceCheckinMode: false,
      clearedAttendeeOverrides: 2,
    });

    const remaining = await prisma.meetingRequiredAttendee.findMany({
      where: { meetingId: meeting.id, checkinMode: { not: null } as any },
    });
    expect(remaining.length).toBe(0);
  });

  it('[2] Meeting OFF→ON 不动 checkinMode，响应不含 clearedAttendeeOverrides', async () => {
    const { adminUser, adminToken } = await loginAsAdmin();
    const { meeting } = await createMeetingWithAttendees({
      creatorId: adminUser.id,
      city: 'Beijing',
      enforceCheckinMode: false,
      attendeeCheckinModes: ['ON_SITE'],
    });

    const resp = await request(app.getHttpServer())
      .patch(`/api/v1/meeting-attendance/meetings/${meeting.id}/enforce-checkin-mode`)
      .set('Authorization', `Bearer ${adminToken}`)
      .send({ enforceCheckinMode: true })
      .expect(200);

    expect(resp.body.enforceCheckinMode).toBe(true);
    expect(resp.body.clearedAttendeeOverrides).toBeUndefined();

    const overrides = await prisma.meetingRequiredAttendee.findMany({
      where: { meetingId: meeting.id, checkinMode: { not: null } as any },
    });
    expect(overrides.length).toBe(1);
  });

  it('[3] Series ON→OFF 级联清空下属所有会议的 MeetingRequiredAttendee.checkinMode', async () => {
    const { adminUser, adminToken } = await loginAsAdmin();
    const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const series = await prisma.meetingSeries.create({
      data: {
        title: `v1.4 Series ${suffix}`,
        pattern: 'WEEKLY',
        frequency: 1,
        startDate: new Date('2026-05-01T00:00:00Z'),
        endDate: new Date('2026-07-01T00:00:00Z'),
        timezone: 'UTC',
        type: 'HYBRID',
        creatorId: adminUser.id,
        isActive: true,
        city: 'Beijing',
        enforceCheckinMode: true,
      } as any,
    });

    const a = await createMeetingWithAttendees({
      creatorId: adminUser.id,
      seriesId: series.id,
      city: 'Beijing',
      enforceCheckinMode: true,
      attendeeCheckinModes: ['ON_SITE', 'ONLINE'],
    });
    const b = await createMeetingWithAttendees({
      creatorId: adminUser.id,
      seriesId: series.id,
      city: 'Beijing',
      enforceCheckinMode: true,
      attendeeCheckinModes: ['ONLINE'],
    });

    const resp = await request(app.getHttpServer())
      .patch(`/api/v1/meeting-attendance/series/${series.id}/enforce-checkin-mode`)
      .set('Authorization', `Bearer ${adminToken}`)
      .send({ enforceCheckinMode: false })
      .expect(200);

    expect(resp.body).toMatchObject({
      seriesId: series.id,
      enforceCheckinMode: false,
      clearedAttendeeOverrides: 3,
    });

    const remainingA = await prisma.meetingRequiredAttendee.findMany({
      where: { meetingId: a.meeting.id, checkinMode: { not: null } as any },
    });
    const remainingB = await prisma.meetingRequiredAttendee.findMany({
      where: { meetingId: b.meeting.id, checkinMode: { not: null } as any },
    });
    expect(remainingA.length).toBe(0);
    expect(remainingB.length).toBe(0);

    const refreshedMeetings = await prisma.meeting.findMany({
      where: { seriesId: series.id },
      select: { id: true, enforceCheckinMode: true } as any,
    });
    for (const m of refreshedMeetings as any[]) {
      expect(m.enforceCheckinMode).toBe(false);
    }
  });

  it('[4] Series ON→OFF 保留 MeetingSeriesAttendeePreference', async () => {
    const { adminUser, adminToken } = await loginAsAdmin();
    const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const series = await prisma.meetingSeries.create({
      data: {
        title: `v1.4 Series Pref ${suffix}`,
        pattern: 'WEEKLY',
        frequency: 1,
        startDate: new Date('2026-05-01T00:00:00Z'),
        endDate: new Date('2026-07-01T00:00:00Z'),
        timezone: 'UTC',
        type: 'HYBRID',
        creatorId: adminUser.id,
        isActive: true,
        city: 'Beijing',
        enforceCheckinMode: true,
      } as any,
    });

    const { users } = await createMeetingWithAttendees({
      creatorId: adminUser.id,
      seriesId: series.id,
      city: 'Beijing',
      enforceCheckinMode: true,
      attendeeCheckinModes: ['ON_SITE'],
    });

    await (prisma as any).meetingSeriesAttendeePreference.create({
      data: {
        seriesId: series.id,
        userId: users[0].id,
        defaultCheckinMode: 'ONLINE',
      },
    });

    await request(app.getHttpServer())
      .patch(`/api/v1/meeting-attendance/series/${series.id}/enforce-checkin-mode`)
      .set('Authorization', `Bearer ${adminToken}`)
      .send({ enforceCheckinMode: false })
      .expect(200);

    const prefs = await (prisma as any).meetingSeriesAttendeePreference.findMany({
      where: { seriesId: series.id },
    });
    expect(prefs.length).toBe(1);
    expect(prefs[0].defaultCheckinMode).toBe('ONLINE');
  });

  it('[5] OFF→ON 后 listRequiredAttendees 从保留的系列级覆盖派生 allowedMode', async () => {
    const { adminUser, adminToken } = await loginAsAdmin();
    const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const series = await prisma.meetingSeries.create({
      data: {
        title: `v1.4 Series Reopen ${suffix}`,
        pattern: 'WEEKLY',
        frequency: 1,
        startDate: new Date('2026-05-01T00:00:00Z'),
        endDate: new Date('2026-07-01T00:00:00Z'),
        timezone: 'UTC',
        type: 'HYBRID',
        creatorId: adminUser.id,
        isActive: true,
        city: 'Beijing',
        enforceCheckinMode: true,
      } as any,
    });

    const { meeting, users } = await createMeetingWithAttendees({
      creatorId: adminUser.id,
      seriesId: series.id,
      city: 'Beijing',
      enforceCheckinMode: true,
      attendeeCheckinModes: ['ON_SITE'], // meeting-level override = ON_SITE
    });

    await (prisma as any).meetingSeriesAttendeePreference.create({
      data: {
        seriesId: series.id,
        userId: users[0].id,
        defaultCheckinMode: 'ONLINE', // 系列级默认 = ONLINE
      },
    });

    // ON→OFF：清空 meeting-level（保留系列级）
    await request(app.getHttpServer())
      .patch(`/api/v1/meeting-attendance/series/${series.id}/enforce-checkin-mode`)
      .set('Authorization', `Bearer ${adminToken}`)
      .send({ enforceCheckinMode: false })
      .expect(200);

    // OFF→ON：重开
    await request(app.getHttpServer())
      .patch(`/api/v1/meeting-attendance/series/${series.id}/enforce-checkin-mode`)
      .set('Authorization', `Bearer ${adminToken}`)
      .send({ enforceCheckinMode: true })
      .expect(200);

    // listRequiredAttendees 应从系列级派生 allowedMode = ONLINE
    const resp = await request(app.getHttpServer())
      .get(`/api/v1/meeting-attendance/meetings/${meeting.id}/required-attendees`)
      .set('Authorization', `Bearer ${adminToken}`)
      .expect(200);

    const items: any[] = resp.body.requiredAttendees ?? resp.body;
    const target = items.find((it) => it.userId === users[0].id || it.user?.id === users[0].id);
    expect(target).toBeDefined();
    expect(target.allowedMode).toBe('ONLINE');
    expect(target.allowedModeSource).toBe('SERIES_PREFERENCE');
    expect(target.checkinMode).toBeNull(); // meeting-level 已被 ON→OFF 清空
  });
});
