import { ForbiddenException, NotFoundException } from '@nestjs/common';
import { ReportEntity } from '../../domain/entities/report.entity';
import { ReportStatus } from '../../domain/enums/report-status.enum';
import { ReportType } from '../../domain/enums/report-type.enum';
import { type IReportRepository } from '../../domain/repositories/report.repository';
import { DeleteReportCommand } from '../commands/delete-report/delete-report.command';
import { DeleteReportHandler } from '../commands/delete-report/delete-report.handler';

function createReport(userId = 'user-1'): ReportEntity {
  return new ReportEntity('rpt-1', {
    userId,
    type: ReportType.RESIDENTIAL_MARKET,
    title: 'Test Report',
    params: {},
    content: null,
    pdfUrl: null,
    status: ReportStatus.READY,
    errorMsg: null,
  });
}

describe('DeleteReportHandler', () => {
  let handler: DeleteReportHandler;
  let mockReportRepo: { [K in keyof IReportRepository]: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    mockReportRepo = {
      findById: vi.fn(),
      findByUserId: vi.fn(),
      save: vi.fn(),
      update: vi.fn(),
      delete: vi.fn(),
      countByUserInPeriod: vi.fn(),
    };

    handler = new DeleteReportHandler(mockReportRepo as any);
  });

  it('deletes a report owned by the user', async () => {
    mockReportRepo.findById.mockResolvedValue(createReport('user-1'));

    await handler.execute(new DeleteReportCommand('rpt-1', 'user-1'));

    expect(mockReportRepo.delete).toHaveBeenCalledWith('rpt-1');
  });

  it('throws NotFoundException when report does not exist', async () => {
    mockReportRepo.findById.mockResolvedValue(null);

    await expect(
      handler.execute(new DeleteReportCommand('nonexistent', 'user-1')),
    ).rejects.toThrow(NotFoundException);
  });

  it('throws ForbiddenException when user does not own report', async () => {
    mockReportRepo.findById.mockResolvedValue(createReport('other-user'));

    await expect(
      handler.execute(new DeleteReportCommand('rpt-1', 'user-1')),
    ).rejects.toThrow(ForbiddenException);
  });
});
