/**
 * L1 集成测试 — site-attendance 事件导出 CSV 时区格式
 *
 * 覆盖：
 *   - GET /checkpoints/:id/events/export 返回 CSV
 *   - header `Time` 列带 checkpoint.timezone 标注
 *   - 时间列按 cp.timezone 渲染为 `YYYY-MM-DD HH:mm:ss`，不再是 UTC ISO
 *   - 不同 timezone 的 checkpoint 各自渲染自己的本地时间
 */

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

describe('Site Attendance Export Events CSV - L1', () => {
  let app: INestApplication;
  let prisma: PrismaService;
  let adminToken: string;
  let userId: string;

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

  beforeEach(async () => {
    const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const admin = await createAdminUser({
      username: `t_exp_admin_${suffix}`,
      email: `t_exp_admin_${suffix}@example.com`,
      password: 'Admin@123',
      displayName: 't_Export Admin',
    });
    const user = await createTestUser({
      username: `t_exp_user_${suffix}`,
      email: `t_exp_user_${suffix}@example.com`,
      password: 'User@1234',
      displayName: 't_Export User',
    });
    userId = user.id;

    const adminLogin = await request(app.getHttpServer())
      .post('/api/v1/auth/login')
      .send({ username: admin.username, password: 'Admin@123' })
      .expect(200);
    adminToken = adminLogin.body.data.accessToken as string;
  });

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

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

  async function createCheckpoint(timezone: string) {
    const res = await request(app.getHttpServer())
      .post('/api/v1/site-attendance/checkpoints')
      .set('Authorization', `Bearer ${adminToken}`)
      .send({
        name: `t_CP-${Math.random().toString(36).slice(2, 8)}`,
        timezone,
        latitude: 34.05,
        longitude: -118.24,
        accessMode: 'PUBLIC',
        geoPolicy: 'SKIP',
      })
      .expect(201);
    return res.body.data;
  }

  async function fetchExport(checkpointId: string, date: string): Promise<string[]> {
    const res = await request(app.getHttpServer())
      .get(`/api/v1/site-attendance/checkpoints/${checkpointId}/events/export`)
      .query({ date })
      .set('Authorization', `Bearer ${adminToken}`)
      .expect(200);
    expect(res.headers['content-type']).toMatch(/text\/csv/);
    // controller 会预置 BOM (﻿)，剥掉再按行切
    const body = String(res.text).replace(/^﻿/, '');
    return body.split('\n');
  }

  it('LA checkpoint: header carries timezone, time column rendered in LA local', async () => {
    const cp = await createCheckpoint('America/Los_Angeles');
    // 2026-05-05T16:40:45Z → LA 2026-05-05 09:40:45 (PDT, UTC-7)
    // 09:40 ≥ 5am workday boundary → localDate = 2026-05-05
    await prisma.siteAttendanceEvent.create({
      data: {
        checkpointId: cp.id,
        userId,
        eventType: 'CHECK_IN',
        timestamp: new Date('2026-05-05T16:40:45Z'),
        localDate: '2026-05-05',
        authMethod: 'AUTHENTICATED',
        geoStatus: 'SKIPPED',
      },
    });

    const lines = await fetchExport(cp.id, '2026-05-05');

    expect(lines[0]).toContain('Time (America/Los_Angeles)');
    expect(lines[0]).not.toMatch(/,Time,/);
    expect(lines).toHaveLength(2);

    const cells = lines[1].split(',');
    // [name, email, type, time, auth, geo, distance, accuracy, location]
    // 后缀 PDT 既体现 DST，也防止 Excel 把整列识别为 datetime 触发默认 format 吞秒
    expect(cells[3]).toBe('2026-05-05 09:40:45 PDT');
    expect(cells[3]).not.toMatch(/Z$/);
    expect(cells[3]).not.toMatch(/T\d{2}/);
  });

  it('Asia/Shanghai checkpoint: same UTC instant rendered in +08 local', async () => {
    const cp = await createCheckpoint('Asia/Shanghai');
    // 2026-05-05T06:00:00Z → SH 2026-05-05 14:00:00 (UTC+8)
    // 14:00 ≥ 5am → localDate = 2026-05-05
    await prisma.siteAttendanceEvent.create({
      data: {
        checkpointId: cp.id,
        userId,
        eventType: 'CHECK_OUT',
        timestamp: new Date('2026-05-05T06:00:00Z'),
        localDate: '2026-05-05',
        authMethod: 'AUTHENTICATED',
        geoStatus: 'SKIPPED',
      },
    });

    const lines = await fetchExport(cp.id, '2026-05-05');

    expect(lines[0]).toContain('Time (Asia/Shanghai)');

    const cells = lines[1].split(',');
    // ICU 给 Asia/Shanghai 的 short tz 是 GMT+8（避免和美国 CST 撞）
    expect(cells[3]).toBe('2026-05-05 14:00:00 GMT+8');
  });

  it('time column DST-aware: Jan event in LA is PST (-08), May event is PDT (-07)', async () => {
    const cp = await createCheckpoint('America/Los_Angeles');
    // PST window: 2026-01-15T08:00:00Z → LA 2026-01-15 00:00:00 (UTC-8)
    // 00:00 < 5am → localDate = 2026-01-14
    await prisma.siteAttendanceEvent.create({
      data: {
        checkpointId: cp.id,
        userId,
        eventType: 'CHECK_IN',
        timestamp: new Date('2026-01-15T08:00:00Z'),
        localDate: '2026-01-14',
        authMethod: 'AUTHENTICATED',
        geoStatus: 'SKIPPED',
      },
    });

    const lines = await fetchExport(cp.id, '2026-01-14');
    const cells = lines[1].split(',');
    // PST 时区下 UTC 08:00 应该是当地 00:00（不是 PDT 的 01:00）；后缀显式 PST 区分 5月的 PDT
    expect(cells[3]).toBe('2026-01-15 00:00:00 PST');
  });
});
