import { NotFoundException } from '@nestjs/common';
import { PantryService } from './pantry.service';

describe('PantryService IDOR security', () => {
  const makeCreatePantryDto = (overrides: Partial<{ productId: number; userId: number }> = {}) => ({
    productId: 1,
    ...overrides,
  });

  const prismaMock = {
    pantryItem: {
      findMany: jest.fn(),
      findUnique: jest.fn(),
      findFirst: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
      delete: jest.fn(),
    },
    product: {
      findUnique: jest.fn(),
    },
    user: {
      findUnique: jest.fn(),
    },
    inventoryItem: {
      create: jest.fn(),
    },
    $transaction: jest.fn(),
  };

  const service = new PantryService(prismaMock as any);

  beforeEach(() => {
    jest.clearAllMocks();
  });

  const mockPantryFindManyEmpty = () => {
    prismaMock.pantryItem.findMany.mockResolvedValue([]);
  };

  it('scopar findAll till userId', async () => {
    mockPantryFindManyEmpty();

    await service.findAll(42);

    expect(prismaMock.pantryItem.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({ userId: 42 }),
      }),
    );
  });

  it('findAllAdmin kan filtrera per userId', async () => {
    mockPantryFindManyEmpty();

    await service.findAllAdmin({ userId: 99 });

    expect(prismaMock.pantryItem.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({ userId: 99 }),
      }),
    );
  });

  it('findAllAdmin returnerar alla items om userId inte specificeras', async () => {
    mockPantryFindManyEmpty();

    await service.findAllAdmin({});

    expect(prismaMock.pantryItem.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: {},
      }),
    );
  });

  it('create sätter userId på nya pantry-items', async () => {
    prismaMock.product.findUnique.mockResolvedValue({ id: 1 });
    prismaMock.pantryItem.create.mockResolvedValue({ id: 1, userId: 42 });

    await service.create(42, makeCreatePantryDto() as any);

    expect(prismaMock.pantryItem.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({ userId: 42, productId: 1 }),
      }),
    );
  });

  it('createAdmin kan skapa pantry-item för explicit userId', async () => {
    prismaMock.user.findUnique.mockResolvedValue({ id: 99 });
    prismaMock.product.findUnique.mockResolvedValue({ id: 1 });
    prismaMock.pantryItem.create.mockResolvedValue({ id: 1, userId: 99 });

    await service.createAdmin(1, makeCreatePantryDto({ userId: 99 }) as any, 99);

    expect(prismaMock.pantryItem.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({ userId: 99, productId: 1 }),
      }),
    );
  });

  it('createAdmin throws NotFoundException om target user saknas', async () => {
    prismaMock.user.findUnique.mockResolvedValue(null);

    await expect(service.createAdmin(1, makeCreatePantryDto({ userId: 999 }) as any, 999)).rejects.toThrow(
      NotFoundException,
    );
  });

  it('remove nekar icke-owner', async () => {
    // Simulera att item inte hittas (userId matchar inte)
    prismaMock.pantryItem.findFirst.mockResolvedValue(null);

    await expect(service.remove(42, 1)).rejects.toThrow(NotFoundException);
  });

  it('moveToInventory nekar icke-owner', async () => {
    // Simulera att item inte hittas (userId matchar inte)
    prismaMock.pantryItem.findFirst.mockResolvedValue(null);

    await expect(service.moveToInventory(42, 1, {} as any)).rejects.toThrow(NotFoundException);
  });
});
