/**
 * L1 集成测试 — form-management instance 状态机基线
 *
 * 锁定 PR #208 的关键修复，防止后续回归：
 *   - 撤回语义统一为 WITHDRAWN（form + approval 双向，CANCELLED 仅留给系统强制取消）
 *   - withdrawFormWithApproval 的 createdBy IDOR 校验
 *   - handleApprovalCompleted 回调中 endReason=WITHDRAWN → FormInstance.WITHDRAWN
 *   - 状态机：DRAFT→PENDING_APPROVAL→WITHDRAWN / DRAFT→SUBMITTED 路径
 *   - resubmit 路径：REJECTED/WITHDRAWN → submit 允许；其他状态拒绝
 *
 * 范围：纯 form-management 状态机 + form-engine 回调，不依赖 Temporal worker
 * 真正运行（部分场景通过直接 prisma 注入跨过 submit 的工作流启动步骤）。
 */

import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { PrismaService } from '@/core/database/prisma/prisma.service';
import { ApprovalService } from '@/engines/approval/approval.service';
import { FormApprovalIntegrationService } from '@/engines/form/form-engine/services/form-approval-integration.service';
import { createTestApp } from '../../helpers/app.helper';
import { cleanupByPrefix } from '../../helpers/cleanup.helper';
import { createAdminUser } from '../../helpers/factories/user.factory';
import {
  cleanupFormManagementTestData,
  createTestFormDefinition,
  createTestFormInstance,
  fakeApprovalInstanceId,
  TestFormDefinition,
} from './_helpers';

describe('form-management instance state machine - L1', () => {
  let app: INestApplication;
  let prisma: PrismaService;
  let approvalIntegration: FormApprovalIntegrationService;

  // 用 admin 账号跑 API（form:use 权限需要）。
  // userA 是真实登录用户；userB 是 IDOR 测试用，从 prisma 直接造（避免双 createAdminUser 的 FK 状态污染）
  let userAToken: string;
  let userAId: string;
  let userBToken: string;
  let userBId: string;
  let definition: TestFormDefinition;

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

  beforeEach(async () => {
    const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;

    const userA = await createAdminUser({
      username: `t_fminst_a_${suffix}`,
      email: `t_fminst_a_${suffix}@example.com`,
      password: 'Admin@123',
      displayName: 't_FmInst UserA',
    });
    const userB = await createAdminUser({
      username: `t_fminst_b_${suffix}`,
      email: `t_fminst_b_${suffix}@example.com`,
      password: 'Admin@123',
      displayName: 't_FmInst UserB',
    });
    userAId = userA.id;
    userBId = userB.id;

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

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

    // 默认创建一个不需审批的表单定义；需审批的子用例自己造
    definition = await createTestFormDefinition(prisma, {
      prefix: 't_fminst',
      createdBy: userAId,
      requiresApproval: false,
    });
  });

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

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

  // ============================================================
  // 1. 基本生命周期：create → update → submit (无审批) → SUBMITTED
  // ============================================================
  describe('lifecycle without approval', () => {
    it('create → DRAFT', async () => {
      const res = await request(app.getHttpServer())
        .post('/api/v1/form-management/instances')
        .set('Authorization', `Bearer ${userAToken}`)
        .set('X-Region-Id', 'CN')
        .send({
          formDefinitionId: definition.definitionId,
          formData: { amount: 1000, reason: 't_create' },
        })
        .expect(201);
      expect(res.body.data.formInstance.status).toBe('DRAFT');
    });

    it('update DRAFT → 数据持久化', async () => {
      const created = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'DRAFT',
      });

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

      const after = await prisma.formInstance.findUnique({ where: { id: created.id } });
      expect((after!.data as any).amount).toBe(9999);
      expect((after!.data as any).reason).toBe('t_updated');
    });

    it('submit DRAFT 无审批要求 → SUBMITTED', async () => {
      const created = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'DRAFT',
      });

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

      const after = await prisma.formInstance.findUnique({ where: { id: created.id } });
      expect(after!.status).toBe('SUBMITTED');
      expect(after!.submittedAt).not.toBeNull();
      expect(after!.approvalInstanceId).toBeNull();
    });
  });

  // ============================================================
  // 2. 撤回路径（PR #208 核心：终态 WITHDRAWN，不是 CANCELLED）
  // ============================================================
  describe('withdraw — PR #208 关键修复', () => {
    it('PENDING_APPROVAL → WITHDRAWN（form 双向 WITHDRAWN，不是 CANCELLED）', async () => {
      // approvalInstanceId 用 UUID 占位即可：approvalService.withdraw 已被 spy 屏蔽
      const fakeApprovalId = fakeApprovalInstanceId();
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'PENDING_APPROVAL',
        approvalInstanceId: fakeApprovalId,
        approvalStatus: 'RUNNING',
      });

      // approvalService.withdraw 内部会调 Temporal sendSignal，本地无 worker 时会 throw
      jest.spyOn(app.get(ApprovalService), 'withdraw').mockResolvedValue({
        success: true,
        instanceId: fakeApprovalId,
        status: 'WITHDRAWN',
      } as any);

      const res = await request(app.getHttpServer())
        .post(`/api/v1/form-management/instances/${inst.id}/withdraw`)
        .set('Authorization', `Bearer ${userAToken}`)
        .set('X-Region-Id', 'CN')
        .send({ reason: 't_withdraw_reason' });
      expect([200, 201]).toContain(res.status);
      expect(res.body.data.status).toBe('WITHDRAWN');

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      // 锁定 PR #208：不是 CANCELLED
      expect(after!.status).toBe('WITHDRAWN');
      expect(after!.approvalStatus).toBe('WITHDRAWN');
      expect(after!.approvalEndTime).not.toBeNull();
    });

    it('IDOR：非 createdBy 用户撤回 → 403', async () => {
      const fakeApprovalId = fakeApprovalInstanceId();
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'PENDING_APPROVAL',
        approvalInstanceId: fakeApprovalId,
      });

      // userB 尝试撤回 userA 创建的实例（接受 403/404 都算防护成功）
      const res = await request(app.getHttpServer())
        .post(`/api/v1/form-management/instances/${inst.id}/withdraw`)
        .set('Authorization', `Bearer ${userBToken}`)
        .set('X-Region-Id', 'CN')
        .send({ reason: 't_idor_attempt' });
      expect([403, 404]).toContain(res.status);

      // userA 自己撤回必须仍然成功（防止守卫错杀）
      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      expect(after!.status).toBe('PENDING_APPROVAL'); // 未被 userB 改动
    });

    it('状态守卫：DRAFT 状态撤回 → 拒绝', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'DRAFT',
      });

      const res = await request(app.getHttpServer())
        .post(`/api/v1/form-management/instances/${inst.id}/withdraw`)
        .set('Authorization', `Bearer ${userAToken}`)
        .set('X-Region-Id', 'CN')
        .send({});

      expect([400, 422]).toContain(res.status);

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      expect(after!.status).toBe('DRAFT');
    });
  });

  // ============================================================
  // 3. handleApprovalCompleted 回调（PR #208：endReason=WITHDRAWN → WITHDRAWN）
  // ============================================================
  describe('handleApprovalCompleted callback unification', () => {
    it('endReason=WITHDRAWN → FormInstance.status = WITHDRAWN（不是 CANCELLED）', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'PENDING_APPROVAL',
        approvalStatus: 'RUNNING',
      });

      await approvalIntegration.handleApprovalCompleted({
        approvalInstanceId: 't_fake',
        businessId: inst.id,
        status: 'TERMINATED',
        endReason: 'WITHDRAWN',
        endTime: new Date().toISOString(),
      } as any);

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      // 锁定 PR #208 修复：之前会落 CANCELLED，现在应是 WITHDRAWN
      expect(after!.status).toBe('WITHDRAWN');
    });

    it('endReason=REJECTED → REJECTED（已有路径未受 polish PR 影响，回归基线）', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'PENDING_APPROVAL',
        approvalStatus: 'RUNNING',
      });

      await approvalIntegration.handleApprovalCompleted({
        approvalInstanceId: 't_fake',
        businessId: inst.id,
        status: 'TERMINATED',
        endReason: 'REJECTED',
        endTime: new Date().toISOString(),
      } as any);

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      expect(after!.status).toBe('REJECTED');
    });

    it('status=COMPLETED → APPROVED', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'PENDING_APPROVAL',
        approvalStatus: 'RUNNING',
      });

      await approvalIntegration.handleApprovalCompleted({
        approvalInstanceId: 't_fake',
        businessId: inst.id,
        status: 'COMPLETED',
        endTime: new Date().toISOString(),
      } as any);

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      expect(after!.status).toBe('APPROVED');
    });
  });

  // ============================================================
  // 4. Resubmit 路径（PR #208 P0 #131）
  // ============================================================
  describe('resubmit — REJECTED / WITHDRAWN 状态可重新 submit', () => {
    it('REJECTED → update → submit → SUBMITTED（无审批要求场景）', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'REJECTED',
        data: { amount: 1, reason: 't_initial' },
      });

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

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

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      expect(after!.status).toBe('SUBMITTED');
      expect((after!.data as any).amount).toBe(8888);
    });

    it('WITHDRAWN → submit → SUBMITTED', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'WITHDRAWN',
      });

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

      const after = await prisma.formInstance.findUnique({ where: { id: inst.id } });
      expect(after!.status).toBe('SUBMITTED');
    });

    it('APPROVED 状态不允许 resubmit', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'APPROVED',
      });

      const res = await request(app.getHttpServer())
        .post(`/api/v1/form-management/instances/${inst.id}/submit`)
        .set('Authorization', `Bearer ${userAToken}`)
        .set('X-Region-Id', 'CN')
        .send({});

      expect([400, 422, 500]).toContain(res.status);
    });

    it('PENDING_APPROVAL 状态不允许 update', async () => {
      const inst = await createTestFormInstance(prisma, {
        definition,
        createdBy: userAId,
        status: 'PENDING_APPROVAL',
      });

      const res = await request(app.getHttpServer())
        .patch(`/api/v1/form-management/instances/${inst.id}`)
        .set('Authorization', `Bearer ${userAToken}`)
        .set('X-Region-Id', 'CN')
        .send({ formData: { amount: 1, reason: 't_blocked' } });

      expect([400, 422]).toContain(res.status);
    });
  });
});
