import { ForbiddenException } from '@nestjs/common';
import { TripPreferenceOverridesController } from './trip-preference-overrides.controller';
import type { AuthenticatedUser } from '../../../../libs/auth/src';

describe('TripPreferenceOverridesController', () => {
  const member: AuthenticatedUser = {
    id: 'u1',
    externalSubjectId: 'sub-1',
    displayName: 'Alex',
    email: 'a@example.com',
  };

  it('GET /trips/:tripId/preference-overrides lists overrides', async () => {
    const service = { listOverrides: jest.fn().mockResolvedValue([]) };
    const controller = new TripPreferenceOverridesController(service as never);

    await expect(controller.list('t1')).resolves.toEqual([]);
    expect(service.listOverrides).toHaveBeenCalledWith('t1');
  });

  it('allows a member to upsert their own USER override', async () => {
    const dto = {
      subject: { type: 'USER' as const, userId: 'u1' },
      overrides: { preferredPace: 'fast' },
    };
    const updated = { id: 'o1', tripId: 't1', ...dto };
    const service = { upsertOverride: jest.fn().mockResolvedValue(updated) };
    const controller = new TripPreferenceOverridesController(service as never);

    await expect(
      controller.upsert('t1', member, 'MEMBER', dto),
    ).resolves.toEqual(updated);
    expect(service.upsertOverride).toHaveBeenCalledWith(
      't1',
      dto.subject,
      dto.overrides,
    );
  });

  it('denies a non-owner member from setting another user override', async () => {
    const dto = {
      subject: { type: 'USER' as const, userId: 'someone-else' },
      overrides: {},
    };
    const service = { upsertOverride: jest.fn() };
    const controller = new TripPreferenceOverridesController(service as never);

    await expect(
      controller.upsert('t1', member, 'MEMBER', dto),
    ).rejects.toThrow(ForbiddenException);
    expect(service.upsertOverride).not.toHaveBeenCalled();
  });

  it('denies a non-owner member from setting a traveler override', async () => {
    const dto = {
      subject: { type: 'TRAVELER' as const, travelerId: 'trav-1' },
      overrides: {},
    };
    const service = { upsertOverride: jest.fn() };
    const controller = new TripPreferenceOverridesController(service as never);

    await expect(
      controller.upsert('t1', member, 'MEMBER', dto),
    ).rejects.toThrow(ForbiddenException);
  });

  it('allows an OWNER to set overrides for any subject', async () => {
    const dto = {
      subject: { type: 'TRAVELER' as const, travelerId: 'trav-1' },
      overrides: {},
    };
    const updated = { id: 'o1', tripId: 't1', ...dto };
    const service = { upsertOverride: jest.fn().mockResolvedValue(updated) };
    const controller = new TripPreferenceOverridesController(service as never);

    await expect(
      controller.upsert('t1', member, 'OWNER', dto),
    ).resolves.toEqual(updated);
  });

  it('DELETE /trips/:tripId/preference-overrides/:overrideId removes an override', async () => {
    const service = { removeOverride: jest.fn().mockResolvedValue(undefined) };
    const controller = new TripPreferenceOverridesController(service as never);

    await controller.remove('t1', 'o1');
    expect(service.removeOverride).toHaveBeenCalledWith('t1', 'o1');
  });
});
