import { Decimal } from '@prisma/client/runtime/library';
import { CashbackService } from './cashback.service';

describe('CashbackService previewBatch', () => {
  const tx = {
    cashbackBatch: {
      findMany: jest.fn(),
      create: jest.fn(),
    },
    cashbackItem: {
      create: jest.fn(),
    },
    cashbackBet: {
      create: jest.fn(),
    },
  };
  const prisma = {
    cashbackBatch: {
      findFirst: jest.fn(),
    },
    cashbackBet: {
      findMany: jest.fn(),
    },
    bet: {
      findMany: jest.fn(),
    },
    cashbackRule: {
      findMany: jest.fn(),
    },
    agentProfile: {
      findMany: jest.fn(),
    },
    user: {
      findMany: jest.fn(),
    },
    wallet: {
      findMany: jest.fn(),
    },
    $transaction: jest.fn(async (fn: (client: typeof tx) => Promise<unknown>) => fn(tx)),
  };
  const funds = {};
  const systemConfig = {
    getPlatformDirectCashbackSettings: jest.fn(),
  };

  let service: CashbackService;

  const platformPlayerId = 100n;
  const adminInvitePlayerId = 101n;
  const adminSponsorId = 200n;
  const periodStart = new Date('2026-06-01T00:00:00.000Z');
  const periodEnd = new Date('2026-06-01T23:59:59.999Z');

  beforeEach(() => {
    jest.clearAllMocks();
    service = new CashbackService(prisma as never, funds as never, systemConfig as never);
    systemConfig.getPlatformDirectCashbackSettings.mockResolvedValue({
      platformDirectRate: 0.02,
      adminInviteRate: 0.05,
    });
    prisma.cashbackBatch.findFirst.mockResolvedValue(null);
    prisma.cashbackBet.findMany.mockResolvedValue([]);
    prisma.cashbackRule.findMany.mockResolvedValue([]);
    prisma.agentProfile.findMany.mockResolvedValue([]);
    tx.cashbackBatch.findMany.mockResolvedValue([]);
    tx.cashbackItem.create.mockResolvedValue({});
    tx.cashbackBet.create.mockResolvedValue({});
    tx.cashbackBatch.create.mockImplementation(({ data }: { data: Record<string, unknown> }) =>
      Promise.resolve({ id: 1n, batchNo: 'CB-TEST', ...data }),
    );
  });

  it('uses platformDirectRate for platform-direct players', async () => {
    prisma.bet.findMany.mockResolvedValue([
      {
        id: 1n,
        userId: platformPlayerId,
        stake: new Decimal(1000),
        status: 'WON',
        settledAt: new Date('2026-06-01T12:00:00.000Z'),
        user: { id: platformPlayerId, parentId: null, inviteSponsorId: null },
        selections: [{ marketType: 'FT_1X2' }],
      },
    ]);
    prisma.user.findMany.mockResolvedValue([
      { id: platformPlayerId, username: 'pd1', parent: null },
    ]);
    prisma.wallet.findMany.mockResolvedValue([
      { userId: platformPlayerId, availableBalance: new Decimal(0) },
    ]);

    const result = await service.previewBatch(periodStart, periodEnd);
    expect(result.items).toHaveLength(1);
    expect(result.items[0].amount.toString()).toBe('20');
    expect(result.totalAmount.toString()).toBe('20');
  });

  it('uses adminInviteRate for admin-invited platform-direct players', async () => {
    prisma.bet.findMany.mockResolvedValue([
      {
        id: 2n,
        userId: adminInvitePlayerId,
        stake: new Decimal(1000),
        status: 'LOST',
        settledAt: new Date('2026-06-01T12:00:00.000Z'),
        user: {
          id: adminInvitePlayerId,
          parentId: null,
          inviteSponsorId: adminSponsorId,
        },
        selections: [{ marketType: 'FT_1X2' }],
      },
    ]);
    prisma.user.findMany
      .mockResolvedValueOnce([{ id: adminSponsorId, userType: 'ADMIN' }])
      .mockResolvedValueOnce([{ id: adminInvitePlayerId, username: 'inv1', parent: null }]);
    prisma.wallet.findMany.mockResolvedValue([
      { userId: adminInvitePlayerId, availableBalance: new Decimal(0) },
    ]);

    const result = await service.previewBatch(periodStart, periodEnd);
    expect(result.items).toHaveLength(1);
    expect(result.items[0].amount.toString()).toBe('50');
    expect(result.totalAmount.toString()).toBe('50');
  });
});
