import { BadRequestException } from '@nestjs/common';
import { BillsService } from './bills.service';

describe('BillsService.purge', () => {
  const createService = (overrides?: { bill?: Record<string, unknown> }) => {
    const bill = {
      id: 1,
      studentId: 2,
      status: 'cancelled',
      paidAmount: 0,
      ...overrides?.bill,
    };
    const billRepo = {
      findOne: jest.fn().mockResolvedValue(bill),
      find: jest.fn().mockResolvedValue([bill]),
    };
    const personalExpRepo = { count: jest.fn().mockResolvedValue(0) };
    const manager = {
      delete: jest.fn().mockResolvedValue({ affected: 1 }),
    };
    const dataSource = {
      transaction: jest.fn(async (cb: (m: unknown) => Promise<unknown>) => cb(manager)),
    };
    const service = new BillsService(
      billRepo as never,
      {} as never,
      {} as never,
      personalExpRepo as never,
      {} as never,
      {} as never,
      dataSource as never,
      {} as never,
    );
    return { service, billRepo, personalExpRepo, dataSource, manager };
  };

  it('rejects bills that are not cancelled', async () => {
    const { service, dataSource } = createService({ bill: { status: 'unpaid' } });
    await expect(service.purge(1)).rejects.toThrow(
      new BadRequestException('仅已取消账单可以永久删除，请先取消账单'),
    );
    expect(dataSource.transaction).not.toHaveBeenCalled();
  });

  it('rejects cancelled bills with paid amount', async () => {
    const { service, dataSource } = createService({ bill: { paidAmount: 100 } });
    await expect(service.purge(1)).rejects.toThrow(
      new BadRequestException('已发生资金流水的账单不能永久删除'),
    );
    expect(dataSource.transaction).not.toHaveBeenCalled();
  });

  it('rejects cancelled bills still referenced by personal expenses', async () => {
    const { service, personalExpRepo, dataSource } = createService();
    personalExpRepo.count.mockResolvedValue(1);
    await expect(service.purge(1)).rejects.toThrow(
      new BadRequestException('该账单仍关联个人费用，无法永久删除'),
    );
    expect(dataSource.transaction).not.toHaveBeenCalled();
  });

  it('deletes bill items and bill in a transaction', async () => {
    const { service, dataSource, manager } = createService();
    await expect(service.purge(1)).resolves.toEqual({
      message: '已永久删除账单（不可恢复）',
    });
    expect(dataSource.transaction).toHaveBeenCalled();
    expect(manager.delete).toHaveBeenNthCalledWith(1, expect.anything(), { billId: 1 });
    expect(manager.delete).toHaveBeenNthCalledWith(2, expect.anything(), 1);
  });
});
