import { AppDataV23SyncService } from './app-data-v23-sync.service';

describe('AppDataV23SyncService', () => {
  const makeDelegate = () => ({
    createMany: jest.fn().mockResolvedValue({ count: 0 }),
    deleteMany: jest.fn().mockResolvedValue({ count: 0 }),
    upsert: jest.fn().mockResolvedValue({}),
  });

  const makePrisma = (snapshot: Record<string, unknown>) => {
    const prisma: any = {
      appData: {
        findMany: jest.fn().mockResolvedValue(
          Object.entries(snapshot).map(([key, value]) => ({
            key,
            value,
          })),
        ),
      },
      user: makeDelegate(),
      product: makeDelegate(),
      project: makeDelegate(),
      version: makeDelegate(),
      taskCategory: makeDelegate(),
      requirement: makeDelegate(),
      versionPlan: makeDelegate(),
      devTask: makeDelegate(),
      testCase: makeDelegate(),
      bug: makeDelegate(),
      workActivity: makeDelegate(),
      taskWorklog: makeDelegate(),
      overtimeRecord: makeDelegate(),
      xiaobaoRiskSnapshot: makeDelegate(),
      xiaobaoRiskInsight: makeDelegate(),
      xiaobaoRiskSummary: makeDelegate(),
      $transaction: jest.fn(async (callback: (tx: any) => Promise<unknown>): Promise<unknown> => callback(prisma)),
    };
    return prisma;
  };

  const productTree = [
    {
      id: 'product-1',
      name: 'Product 1',
      projects: [{ id: 'project-1', name: 'Project 1' }],
      versions: [{ id: 'version-1', projectId: 'project-1', name: 'V1' }],
    },
  ];

  it('replaces requirement rows by product partition scope', async () => {
    const prisma = makePrisma({
      'products-overview': productTree,
      requirements: [
        {
          id: 'req-1',
          productId: 'product-1',
          versionId: 'version-1',
          code: 'REQ-001',
          title: 'Login',
          status: 'adopted',
        },
      ],
    });
    const service = new AppDataV23SyncService(prisma as any);

    await service.syncAfterAppDataPut('requirements');

    expect(prisma.requirement.deleteMany).toHaveBeenCalledWith({
      where: { productId: { in: ['product-1'] } },
    });
    expect(prisma.requirement.createMany).toHaveBeenCalledWith({
      data: [
        expect.objectContaining({
          id: 'req-1',
          productId: 'product-1',
          versionId: 'version-1',
          code: 'REQ-001',
        }),
      ],
      skipDuplicates: true,
    });
  });

  it('replaces version detail rows by version partition scope', async () => {
    const prisma = makePrisma({
      'products-overview': productTree,
      'version-plans': [
        {
          id: 'plan-1',
          versionId: 'version-1',
          type: 'product',
          title: 'PRD',
          status: 'in_progress',
        },
      ],
      'dev-tasks': [
        {
          id: 'dev-1',
          versionId: 'version-1',
          productId: 'product-1',
          projectId: 'project-1',
          code: 'DEV-001',
          title: 'API',
          status: 'in_progress',
        },
      ],
      'test-cases': [
        {
          id: 'tc-1',
          versionId: 'version-1',
          productId: 'product-1',
          projectId: 'project-1',
          code: 'TC-001',
          title: 'Login success',
          status: 'running',
        },
      ],
      bugs: [
        {
          id: 'bug-1',
          versionId: 'version-1',
          productId: 'product-1',
          projectId: 'project-1',
          code: 'BUG-001',
          title: 'Login failure',
          status: 'open',
        },
      ],
    });
    const service = new AppDataV23SyncService(prisma as any);

    await service.syncAfterAppDataPut('dev-tasks');

    expect(prisma.devTask.deleteMany).toHaveBeenCalledWith({
      where: { versionId: { in: ['version-1'] } },
    });
    expect(prisma.devTask.createMany).toHaveBeenCalledWith({
      data: [expect.objectContaining({ id: 'dev-1', versionId: 'version-1', code: 'DEV-001' })],
      skipDuplicates: true,
    });
    expect(prisma.testCase.deleteMany).not.toHaveBeenCalled();
    expect(prisma.bug.deleteMany).not.toHaveBeenCalled();
    expect(prisma.xiaobaoRiskSummary.upsert).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { versionId: 'version-1' },
        update: { dirty: true },
      }),
    );
  });

  it('refreshes Xiaobao summaries from the latest risk snapshot', async () => {
    const prisma = makePrisma({
      'products-overview': productTree,
      'xiaobao-risk-snapshots': [
        {
          id: 'snapshot-1',
          versionId: 'version-1',
          snapshotDate: '2026-07-03',
          riskLevel: 'likely_delayed',
          riskScore: 78,
          confidence: 85,
          forecastReleaseDate: '2026-07-10',
          createdAt: '2026-07-03T10:00:00.000Z',
        },
      ],
    });
    const service = new AppDataV23SyncService(prisma as any);

    await service.syncAfterAppDataPut('xiaobao-risk-snapshots');

    expect(prisma.xiaobaoRiskSnapshot.createMany).toHaveBeenCalledWith({
      data: [expect.objectContaining({ id: 'snapshot-1', versionId: 'version-1', riskScore: 78 })],
      skipDuplicates: true,
    });
    expect(prisma.xiaobaoRiskSummary.upsert).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { versionId: 'version-1' },
        update: expect.objectContaining({
          riskLevel: 'likely_delayed',
          riskScore: 78,
          dirty: false,
        }),
      }),
    );
  });
});
