/**
 * L1 集成测试 — form-management 数据完整性
 *
 * 锁定：
 *   - M11 渲染器对应的 array/object 字段 submit + JSONB 落库结构完整保留
 *   - businessKey 全局唯一约束（schema 上 @unique）
 *   - update 不修改 createdBy / submittedAt 等不可变字段
 *   - 系统注入字段（_applyTime / _regionId / _applicant）随 create 落库
 */

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 } from '../../helpers/factories/user.factory';
import {
  cleanupFormManagementTestData,
  createTestFormDefinition,
  createTestFormInstance,
  TestFormDefinition,
} from './_helpers';

describe('form-management data integrity - L1', () => {
  let app: INestApplication;
  let prisma: PrismaService;

  let userToken: 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, 6)}`;
    const user = await createAdminUser({
      username: `t_fmint_${suffix}`,
      email: `t_fmint_${suffix}@example.com`,
      password: 'Admin@123',
      displayName: 't_FmInt User',
    });
    userId = user.id;

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

  afterEach(async () => {
    await cleanupFormManagementTestData(prisma);
    await cleanupByPrefix(prisma);
  });

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

  // ============================================
  // 1. M11: array / object 字段（明细表 / 嵌套对象 / 多选 / 文件列表）
  // ============================================
  describe('M11 array/object 字段 → JSONB 完整保留', () => {
    let definition: TestFormDefinition;

    beforeEach(async () => {
      definition = await createTestFormDefinition(prisma, {
        prefix: 't_fmint_m11',
        createdBy: userId,
        requiresApproval: false,
        // M11 渲染器对应的字段类型：array of object / nested object / array of string
        schema: {
          type: 'object',
          required: [],
          properties: {
            items: {
              type: 'array',
              title: '明细行',
              items: {
                type: 'object',
                properties: {
                  name: { type: 'string' },
                  qty: { type: 'number' },
                  meta: { type: 'object' },
                },
              },
            },
            address: {
              type: 'object',
              title: '收货地址',
              properties: {
                country: { type: 'string' },
                city: { type: 'string' },
                detail: { type: 'string' },
              },
            },
            tags: {
              type: 'array',
              title: '多选标签',
              items: { type: 'string' },
            },
            attachments: {
              type: 'array',
              title: '附件列表',
              items: {
                type: 'object',
                properties: {
                  url: { type: 'string' },
                  size: { type: 'number' },
                },
              },
            },
          },
        },
      });
    });

    it('create + submit 复杂 JSONB 后字段结构无损', async () => {
      const formData = {
        items: [
          { name: '行 A', qty: 3, meta: { sku: 'SKU-A', tags: ['x', 'y'] } },
          { name: '行 B', qty: 1, meta: { sku: 'SKU-B', nested: { deep: true } } },
        ],
        address: {
          country: 'CN',
          city: '上海',
          detail: '徐汇区 t_addr',
        },
        tags: ['urgent', 'finance', 'q2'],
        attachments: [
          { url: 'https://example.com/a.pdf', size: 1024 },
          { url: 'https://example.com/b.png', size: 2048 },
        ],
      };

      const createRes = await request(app.getHttpServer())
        .post('/api/v1/form-management/instances')
        .set('Authorization', `Bearer ${userToken}`)
        .set('X-Region-Id', 'CN')
        .send({
          formDefinitionId: definition.definitionId,
          formData,
        })
        .expect(201);

      const instanceId = createRes.body.data.formInstance.id;

      await request(app.getHttpServer())
        .post(`/api/v1/form-management/instances/${instanceId}/submit`)
        .set('Authorization', `Bearer ${userToken}`)
        .set('X-Region-Id', 'CN')
        .send({})
        .expect(201);

      const after = await prisma.formInstance.findUnique({ where: { id: instanceId } });
      const data = after!.data as any;

      // 数组顺序、嵌套结构、原始类型全部保留
      expect(data.items).toEqual(formData.items);
      expect(data.items[0].meta.tags).toEqual(['x', 'y']);
      expect(data.items[1].meta.nested.deep).toBe(true);
      expect(data.address).toEqual(formData.address);
      expect(data.tags).toEqual(['urgent', 'finance', 'q2']);
      expect(data.attachments).toEqual(formData.attachments);

      // 系统字段也写入（不破坏用户字段）
      expect(data._applyTime).toBeDefined();
      expect(data._regionId).toBe('CN');
    });

    it('update 写入空数组 / 空对象 → 落库为 [] / {}（不被吞）', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userId,
        status: 'DRAFT',
        data: { items: [{ name: 'old' }], address: { city: 'old' } },
      });

      await request(app.getHttpServer())
        .patch(`/api/v1/form-management/instances/${inst.id}`)
        .set('Authorization', `Bearer ${userToken}`)
        .set('X-Region-Id', 'CN')
        .send({ formData: { items: [], address: {}, tags: [] } })
        .expect(200);

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      const data = after!.data as any;
      expect(Array.isArray(data.items)).toBe(true);
      expect(data.items).toHaveLength(0);
      expect(data.address).toEqual({});
      expect(data.tags).toEqual([]);
    });
  });

  // ============================================
  // 2. businessKey 全局唯一性
  // ============================================
  describe('businessKey 唯一性', () => {
    it('两次 create 生成的 businessKey 不冲突', async () => {
      const definition = await createTestFormDefinition(prisma, {
        prefix: 't_fmint_bk',
        createdBy: userId,
        requiresApproval: false,
      });

      const r1 = await request(app.getHttpServer())
        .post('/api/v1/form-management/instances')
        .set('Authorization', `Bearer ${userToken}`)
        .set('X-Region-Id', 'CN')
        .send({ formDefinitionId: definition.definitionId, formData: {} })
        .expect(201);

      const r2 = await request(app.getHttpServer())
        .post('/api/v1/form-management/instances')
        .set('Authorization', `Bearer ${userToken}`)
        .set('X-Region-Id', 'CN')
        .send({ formDefinitionId: definition.definitionId, formData: {} })
        .expect(201);

      const inst1 = await prisma.formInstance.findUnique({
        where: { id: r1.body.data.formInstance.id },
      });
      const inst2 = await prisma.formInstance.findUnique({
        where: { id: r2.body.data.formInstance.id },
      });

      expect(inst1!.businessKey).toBeTruthy();
      expect(inst2!.businessKey).toBeTruthy();
      expect(inst1!.businessKey).not.toBe(inst2!.businessKey);
    });
  });

  // ============================================
  // 3. update 不改不可变字段
  // ============================================
  describe('update 不修改不可变字段', () => {
    it('PATCH 只改 data，createdBy / createdAt / submittedAt / businessKey 不变', async () => {
      const definition = await createTestFormDefinition(prisma, {
        prefix: 't_fmint_imm',
        createdBy: userId,
        requiresApproval: false,
      });
      const before = await createTestFormInstance(prisma, {
        definition,
        createdBy: userId,
        status: 'DRAFT',
        data: { amount: 1, reason: 't_initial' },
      });

      // 加点延时让 updatedAt 一定 > createdAt（避免同毫秒）
      await new Promise((r) => setTimeout(r, 5));

      await request(app.getHttpServer())
        .patch(`/api/v1/form-management/instances/${before.id}`)
        .set('Authorization', `Bearer ${userToken}`)
        .set('X-Region-Id', 'CN')
        .send({ formData: { amount: 999, reason: 't_updated' } })
        .expect(200);

      const after = await prisma.formInstance.findUnique({ where: { id: before.id } });
      expect(after!.createdBy).toBe(before.createdBy);
      expect(after!.createdAt.toISOString()).toBe(before.createdAt.toISOString());
      expect(after!.businessKey).toBe(before.businessKey);
      expect(after!.submittedAt).toBeNull();
      expect(after!.submittedBy).toBeNull();
      expect((after!.data as any).amount).toBe(999);
    });
  });
});
