import { Decimal } from '@prisma/client/runtime/library';
import { AgentsService } from './agents.service';
import { createPrismaMock } from '../../testing/prisma-mock';

describe('AgentsService', () => {
  const parentAgentId = 1n;
  const createdAgentId = 2n;

  const tx = {
    user: {
      create: jest.fn(),
      findUnique: jest.fn(),
      update: jest.fn(),
    },
    userAuth: {
      create: jest.fn(),
    },
    userPreference: {
      create: jest.fn(),
    },
    userInvite: {
      create: jest.fn(),
      findUnique: jest.fn(),
    },
    agentProfile: {
      create: jest.fn(),
      findUnique: jest.fn(),
    },
    agentClosure: {
      create: jest.fn(),
      findMany: jest.fn(),
    },
  };

  const prisma = createPrismaMock(tx);
  const auth = {
    hashPassword: jest.fn(),
  };
  const systemConfig = {
    getAgentHierarchySettings: jest.fn(),
  };
  const network = {};
  const credit = {
    recalculateUsedCredit: jest.fn(),
  };

  let service: AgentsService;

  beforeEach(() => {
    jest.clearAllMocks();
    service = new AgentsService(
      prisma as never,
      auth as never,
      systemConfig as never,
      network as never,
      credit as never,
    );

    systemConfig.getAgentHierarchySettings.mockResolvedValue({ maxAgentLevel: 3 });
    auth.hashPassword.mockResolvedValue('hashed-password');
    tx.agentProfile.findUnique.mockResolvedValue({
      userId: parentAgentId,
      level: 1,
      creditLimit: new Decimal(1000),
      usedCredit: new Decimal(0),
      cashbackRate: new Decimal(10),
      maxSingleDeposit: null,
      maxDailyDeposit: null,
    });
    tx.user.create.mockResolvedValue({
      id: createdAgentId,
      username: 'agent-child',
      userType: 'AGENT',
    });
    tx.user.findUnique.mockResolvedValue(null);
    tx.user.update.mockResolvedValue({});
    tx.userInvite.findUnique.mockResolvedValue(null);
    tx.userInvite.create.mockResolvedValue({});
    tx.userAuth.create.mockResolvedValue({});
    tx.userPreference.create.mockResolvedValue({});
    tx.agentProfile.create.mockResolvedValue({});
    tx.agentClosure.create.mockResolvedValue({});
    tx.agentClosure.findMany.mockResolvedValue([
      { ancestorId: parentAgentId, depth: 0 },
    ]);
  });

  it('recalculates parent credit exposure after creating a child agent', async () => {
    await service.createAgent(99n, {
      username: 'agent-child',
      password: 'secret',
      level: 2,
      parentAgentId,
      creditLimit: 300,
    });

    expect(credit.recalculateUsedCredit).toHaveBeenCalledWith(parentAgentId);
    expect(credit.recalculateUsedCredit).not.toHaveBeenCalledWith(createdAgentId);
  });
});
