import { NotFoundException } from '@nestjs/common';
import { DevTaskService } from './dev-task.service';

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

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

  it('creates dev tasks 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.devTask.create.mockResolvedValue({ id: 'task-1', versionId: 'version-1', title: '开发登录' });

    await service.create('version-1', {
      requirementId: 'req-1',
      requirementProductId: 'product-1',
      taskNo: 'DEV-001',
      title: '开发登录',
      categoryId: 'cat-fe',
      assigneeId: 'member-1',
      priority: 'P1',
      expectedStartAt: '2026-07-08T09:00:00.000Z',
      expectedEndAt: '2026-07-08T18:00:00.000Z',
      estimateHours: 8,
      references: [{ type: 'requirement', id: 'REQ-001', label: 'REQ-001 登录' }],
      createdBy: 'member-pm',
    } as any);

    expect(prisma.devTask.create).toHaveBeenCalledWith({
      data: expect.objectContaining({
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        requirementId: 'req-1',
        requirementProductId: 'product-1',
        code: 'DEV-001',
        title: '开发登录',
        categoryId: 'cat-fe',
        assigneeId: 'member-1',
        priority: 1,
        expectedStartAt: new Date('2026-07-08T09:00:00.000Z'),
        expectedEndAt: new Date('2026-07-08T18:00:00.000Z'),
        estimateHours: 8,
      }),
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      versionId: 'version-1',
      sourceType: 'dev_task',
      sourceId: 'task-1',
      action: 'dev_task_created',
    }));
  });

  it('changes status by id plus version id and records activity evidence', async () => {
    const { prisma, workActivity, service } = makeService();
    prisma.devTask.findFirst.mockResolvedValue({
      id: 'task-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'todo',
      title: '开发登录',
      assigneeId: 'member-1',
    });
    prisma.devTask.update.mockResolvedValue({
      id: 'task-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'in_progress',
      title: '开发登录',
      assigneeId: 'member-1',
    });

    await service.updateStatus('version-1', 'task-1', 'in_progress');

    expect(prisma.devTask.update).toHaveBeenCalledWith({
      where: { id_versionId: { id: 'task-1', versionId: 'version-1' } },
      data: expect.objectContaining({
        status: 'in_progress',
        startDate: expect.any(Date),
      }),
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      versionId: 'version-1',
      sourceType: 'dev_task',
      sourceId: 'task-1',
      action: 'dev_task_started',
    }));
  });

  it('blocks and unblocks tasks inside the version partition', async () => {
    const { prisma, workActivity, service } = makeService();
    prisma.devTask.findFirst.mockResolvedValue({
      id: 'task-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'in_progress',
      title: '开发登录',
      assigneeId: 'member-1',
    });
    prisma.devTask.update.mockResolvedValue({
      id: 'task-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      isBlocked: true,
      blockReason: '接口未就绪',
      title: '开发登录',
      assigneeId: 'member-1',
    });

    await service.setBlocked('version-1', 'task-1', true, '接口未就绪');

    expect(prisma.devTask.update).toHaveBeenCalledWith({
      where: { id_versionId: { id: 'task-1', versionId: 'version-1' } },
      data: { isBlocked: true, blockReason: '接口未就绪' },
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      action: 'dev_task_blocked',
      metadata: expect.objectContaining({ blocker: '接口未就绪' }),
    }));
  });

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

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