import { UsersService } from './users.service';

describe('UsersService.getStorage', () => {
  const usersRepository = {
    findProfileByUserId: jest.fn(),
    updateProfile: jest.fn(),
    findUserProfile: jest.fn(),
    upsertUserProfile: jest.fn(),
    updatePreferences: jest.fn(),
  };

  const prisma = {
    uploadedFile: {
      findMany: jest.fn(),
    },
    uploadSession: {
      findMany: jest.fn(),
    },
    userMembership: {
      findFirst: jest.fn(),
    },
    accountDeletionRequest: {
      findFirst: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
    },
    userDevice: {
      findMany: jest.fn(),
      deleteMany: jest.fn(),
    },
    knowledgeBase: {
      count: jest.fn(),
    },
    knowledgeItem: {
      count: jest.fn(),
    },
    reviewCard: {
      count: jest.fn(),
    },
  };

  const membershipService = {
    compute: jest.fn(),
    getEntitlements: jest.fn(),
  };

  const quotaService = {
    computeEffectiveQuota: jest.fn(),
  };

  let service: UsersService;

  beforeEach(() => {
    jest.clearAllMocks();
    prisma.uploadedFile.findMany.mockResolvedValue([
      { sizeBytes: BigInt(100), mimeType: 'application/pdf' },
      { sizeBytes: BigInt(50), mimeType: 'image/png' },
    ]);
    prisma.uploadSession.findMany.mockResolvedValue([
      { reservedBytes: BigInt(20) },
      { reservedBytes: BigInt(30) },
    ]);
    quotaService.computeEffectiveQuota.mockResolvedValue({
      limits: [{ quotaType: 'storage_bytes', limit: 500, isUnlimited: false }],
    });
    membershipService.getEntitlements.mockResolvedValue({
      entitlements: { maxStorageBytes: 700 },
    });

    service = new UsersService(
      usersRepository as never,
      prisma as never,
      membershipService as never,
      quotaService as never,
    );
  });

  it('returns committed bytes plus active reservations as usedBytes', async () => {
    const result = await service.getStorage('u1');

    expect(result).toEqual({
      totalBytes: 500,
      usedBytes: 200,
      fileCount: 2,
    });
  });

  it('falls back to membership entitlements when quota lookup fails', async () => {
    quotaService.computeEffectiveQuota.mockRejectedValue(new Error('quota unavailable'));

    const result = await service.getStorage('u1');

    expect(result.totalBytes).toBe(700);
    expect(result.usedBytes).toBe(200);
  });

  it('returns null totalBytes when neither quota nor membership entitlement is available', async () => {
    quotaService.computeEffectiveQuota.mockRejectedValue(new Error('quota unavailable'));
    membershipService.getEntitlements.mockResolvedValue({ entitlements: null });

    const result = await service.getStorage('u1');

    expect(result.totalBytes).toBeNull();
    expect(result.usedBytes).toBe(200);
  });
});
