import { NotFoundException } from '@nestjs/common';
import { BugService } from './bug.service';

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

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

  it('creates bugs 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.bug.create.mockResolvedValue({ id: 'bug-1', versionId: 'version-1', title: '登录报错' });

    await service.create('version-1', {
      bugNo: 'BUG-001',
      testCaseId: 'tc-1',
      title: '登录报错',
      description: '登录按钮无响应',
      severity: 'critical',
      priority: 'P0',
      assigneeId: 'dev-1',
      reportedBy: 'tester-1',
      plannedFixAt: '2026-07-08T18:00:00.000Z',
    } as any);

    expect(prisma.bug.create).toHaveBeenCalledWith({
      data: expect.objectContaining({
        versionId: 'version-1',
        productId: 'product-1',
        projectId: 'project-1',
        testCaseId: 'tc-1',
        testCaseVersionId: 'version-1',
        code: 'BUG-001',
        title: '登录报错',
        severity: 'critical',
        priority: 0,
        assigneeId: 'dev-1',
        reporterId: 'tester-1',
        plannedFixAt: new Date('2026-07-08T18:00:00.000Z'),
        status: 'open',
      }),
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      versionId: 'version-1',
      sourceType: 'bug',
      sourceId: 'bug-1',
      action: 'bug_created',
    }));
  });

  it('changes status and records closing evidence inside the version partition', async () => {
    const { prisma, workActivity, service } = makeService();
    prisma.bug.findFirst.mockResolvedValue({
      id: 'bug-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'verifying',
      title: '登录报错',
      assigneeId: 'dev-1',
      reporterId: 'tester-1',
    });
    prisma.bug.update.mockResolvedValue({
      id: 'bug-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'closed',
      title: '登录报错',
      assigneeId: 'dev-1',
      reporterId: 'tester-1',
    });

    await service.updateStatus('version-1', 'bug-1', 'closed', { operator: 'tester-1', resolution: '复测通过' });

    expect(prisma.bug.update).toHaveBeenCalledWith({
      where: { id_versionId: { id: 'bug-1', versionId: 'version-1' } },
      data: expect.objectContaining({
        status: 'closed',
        closedAt: expect.any(Date),
        resolution: '复测通过',
      }),
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      versionId: 'version-1',
      sourceType: 'bug',
      sourceId: 'bug-1',
      action: 'bug_closed',
    }));
  });

  it('transfers bugs by id plus version id and records activity evidence', async () => {
    const { prisma, workActivity, service } = makeService();
    prisma.bug.findFirst.mockResolvedValue({
      id: 'bug-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      status: 'open',
      title: '登录报错',
      assigneeId: 'dev-1',
      reporterId: 'tester-1',
    });
    prisma.bug.update.mockResolvedValue({
      id: 'bug-1',
      versionId: 'version-1',
      productId: 'product-1',
      projectId: 'project-1',
      title: '登录报错',
      assigneeId: 'dev-2',
      reporterId: 'tester-1',
    });

    await service.transfer('version-1', 'bug-1', 'dev-2', 'tester-1');

    expect(prisma.bug.update).toHaveBeenCalledWith({
      where: { id_versionId: { id: 'bug-1', versionId: 'version-1' } },
      data: { assigneeId: 'dev-2' },
    });
    expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
      action: 'bug_transferred',
      metadata: expect.objectContaining({ fromAssigneeId: 'dev-1', toAssigneeId: 'dev-2' }),
    }));
  });

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

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