import { NotFoundException } from '@nestjs/common';
import { VersionPlanService } from './version-plan.service';

describe('VersionPlanService domain writes', () => {
  const makeService = () => {
    const workActivity = {
      record: jest.fn().mockResolvedValue({ id: 'activity-1' }),
    };
    const prisma = {
      version: {
        findUnique: jest.fn(),
      },
      versionPlan: {
        create: jest.fn(),
        delete: jest.fn(),
        findFirst: jest.fn(),
        findMany: jest.fn(),
        update: jest.fn(),
      },
    };

    return {
      prisma,
      workActivity,
      service: new VersionPlanService(prisma as any, workActivity as any),
    };
  };

  it('creates version plans directly under a version partition', async () => {
    const { prisma, workActivity, service } = makeService();
    prisma.version.findUnique.mockResolvedValue({ id: 'version-1', productId: 'product-1', projectId: 'project-1' });
    prisma.versionPlan.create.mockResolvedValue({ id: 'plan-1', versionId: 'version-1', title: '产品方案' });

    await service.create('version-1', {
      type: 'product',
      title: '产品方案',
      owner: 'member-1',
      startTime: '2026-07-08T09:00:00.000Z',
      endTime: '2026-07-08T18:00:00.000Z',
      linkedRequirementIds: ['req-1'],
    } as any);

    expect(prisma.versionPlan.create).toHaveBeenCalledWith({
      data: expect.objectContaining({
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        type: 'product',
        title: '产品方案',
        ownerId: 'member-1',
        expectedStartAt: new Date('2026-07-08T09:00:00.000Z'),
        expectedEndAt: new Date('2026-07-08T18:00:00.000Z'),
        requirementCoverage: [{ requirementId: 'req-1', status: 'not_started' }],
      }),
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      versionId: 'version-1',
      sourceType: 'version_plan',
      sourceId: 'plan-1',
      action: 'version_plan_created',
    }));
  });

  it('updates plan status inside version scope and records activity evidence', async () => {
    const { prisma, workActivity, service } = makeService();
    prisma.versionPlan.findFirst.mockResolvedValue({
      id: 'plan-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'pending',
      title: '产品方案',
      ownerId: 'member-1',
    });
    prisma.versionPlan.update.mockResolvedValue({
      id: 'plan-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'in_progress',
      title: '产品方案',
      ownerId: 'member-1',
    });

    await service.update('version-1', 'plan-1', { status: 'in_progress' });

    expect(prisma.versionPlan.update).toHaveBeenCalledWith({
      where: { id: 'plan-1' },
      data: expect.objectContaining({
        status: 'in_progress',
        actualStartAt: expect.any(Date),
      }),
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      versionId: 'version-1',
      sourceType: 'version_plan',
      sourceId: 'plan-1',
      action: 'version_plan_started',
    }));
  });

  it('rejects plan updates outside the version partition', async () => {
    const { prisma, service } = makeService();
    prisma.versionPlan.findFirst.mockResolvedValue(null);

    await expect(service.update('version-1', 'missing-plan', { title: 'Ghost' })).rejects.toBeInstanceOf(NotFoundException);
    expect(prisma.versionPlan.update).not.toHaveBeenCalled();
  });
});
