import { NotFoundException } from '@nestjs/common';
import { MealPlanService } from './meal-plan.service';

describe('MealPlanService IDOR security', () => {
  const fromDate = '2026-05-01';
  const toDate = '2026-05-07';

  const prismaMock = {
    mealPlanEntry: {
      findMany: jest.fn(),
      findUnique: jest.fn(),
      upsert: jest.fn(),
      delete: jest.fn(),
    },
    inventoryItem: {
      findMany: jest.fn(),
    },
    pantryItem: {
      findMany: jest.fn(),
    },
    recipe: {
      findUnique: jest.fn(),
    },
    $transaction: jest.fn(),
  };

  const service = new MealPlanService(prismaMock as any);

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

  const mockEmptyRangeData = () => {
    prismaMock.mealPlanEntry.findMany.mockResolvedValue([]);
    prismaMock.inventoryItem.findMany.mockResolvedValue([]);
    prismaMock.pantryItem.findMany.mockResolvedValue([]);
  };

  it('scopar findByRange till userId', async () => {
    mockEmptyRangeData();

    await service.findByRange(42, fromDate, toDate);

    expect(prismaMock.mealPlanEntry.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({
          userId: 42,
          date: expect.any(Object),
        }),
      }),
    );
  });

  it('scopar shoppingList till userId', async () => {
    mockEmptyRangeData();

    await service.shoppingList(42, fromDate, toDate);

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

  it('scopar inventoryCompare till userId', async () => {
    mockEmptyRangeData();

    await service.inventoryCompare(42, fromDate, toDate);

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

  it('upsert sätter userId på nya matplansintrag', async () => {
    prismaMock.mealPlanEntry.upsert.mockResolvedValue({
      id: 1,
      userId: 42,
      date: new Date(),
    });

    await service.upsert(42, { date: '2026-05-11', recipeId: 1 } as any);

    expect(prismaMock.mealPlanEntry.upsert).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({
          userId_date: expect.objectContaining({
            userId: 42,
          }),
        }),
        create: expect.objectContaining({
          userId: 42,
        }),
      }),
    );
  });

  it('removeByDate nekar access för annan user', async () => {
    prismaMock.mealPlanEntry.findUnique.mockResolvedValue(null);

    await expect(service.removeByDate(42, '2026-05-11')).rejects.toThrow(NotFoundException);

    expect(prismaMock.mealPlanEntry.findUnique).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({
          userId_date: expect.objectContaining({
            userId: 42,
          }),
        }),
      }),
    );
  });

  it('removeByDate verifierar userId innan radering', async () => {
    const entry = { id: 1, userId: 42, date: new Date() };
    prismaMock.mealPlanEntry.findUnique.mockResolvedValue(entry);
    prismaMock.mealPlanEntry.delete.mockResolvedValue(entry);

    await service.removeByDate(42, '2026-05-11');

    expect(prismaMock.mealPlanEntry.delete).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({ id: 1 }),
      }),
    );
  });
});
