import { TripsController } from './trips.controller';
import type { AuthenticatedUser } from '../../../../libs/auth/src';

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

  function controllerWith(
    tripsService: object,
    tripSettingsService: object = {},
  ): TripsController {
    return new TripsController(
      tripsService as never,
      tripSettingsService as never,
    );
  }

  it('GET /trips lists trips for the current user', async () => {
    const tripsService = {
      listTripsForUser: jest
        .fn()
        .mockResolvedValue([{ id: 't1', name: 'Slovenia 2027' }]),
    };
    const controller = controllerWith(tripsService);

    await expect(controller.list(currentUser)).resolves.toEqual([
      { id: 't1', name: 'Slovenia 2027' },
    ]);
    expect(tripsService.listTripsForUser).toHaveBeenCalledWith('u1');
  });

  it('POST /trips creates a trip owned by the current user', async () => {
    const created = {
      id: 't1',
      name: 'Slovenia 2027',
      ownerId: 'u1',
      version: 1,
    };
    const tripsService = { createTrip: jest.fn().mockResolvedValue(created) };
    const controller = controllerWith(tripsService);

    await expect(
      controller.create(currentUser, { name: 'Slovenia 2027' }),
    ).resolves.toEqual(created);
    expect(tripsService.createTrip).toHaveBeenCalledWith('u1', {
      name: 'Slovenia 2027',
    });
  });

  it('GET /trips/:tripId returns a single trip', async () => {
    const trip = { id: 't1', name: 'Slovenia 2027' };
    const tripsService = { getTrip: jest.fn().mockResolvedValue(trip) };
    const controller = controllerWith(tripsService);

    await expect(controller.getOne('t1')).resolves.toEqual(trip);
  });

  it('PATCH /trips/:tripId forwards the update dto including version', async () => {
    const updated = { id: 't1', name: 'New name', version: 2 };
    const tripsService = { updateTrip: jest.fn().mockResolvedValue(updated) };
    const controller = controllerWith(tripsService);

    await expect(
      controller.update('t1', { name: 'New name', version: 1 }),
    ).resolves.toEqual(updated);
    expect(tripsService.updateTrip).toHaveBeenCalledWith('t1', {
      name: 'New name',
      version: 1,
    });
  });

  it('DELETE /trips/:tripId deletes the trip', async () => {
    const tripsService = { deleteTrip: jest.fn().mockResolvedValue(undefined) };
    const controller = controllerWith(tripsService);

    await controller.remove('t1');
    expect(tripsService.deleteTrip).toHaveBeenCalledWith('t1');
  });

  it('GET /trips/:tripId/settings returns the trip settings', async () => {
    const settings = { tripId: 't1', webResearchEnabled: false };
    const tripSettingsService = {
      getSettings: jest.fn().mockResolvedValue(settings),
    };
    const controller = controllerWith({}, tripSettingsService);

    await expect(controller.getSettings('t1')).resolves.toEqual(settings);
    expect(tripSettingsService.getSettings).toHaveBeenCalledWith('t1');
  });

  it('PUT /trips/:tripId/settings replaces the trip settings', async () => {
    const dto = {
      webResearchEnabled: true,
      periodicAgentReviewEnabled: false,
      notificationEmailEnabled: true,
      notificationPushEnabled: true,
      defaultResearchDepth: null,
      defaultPlanningStyle: null,
    };
    const updated = { tripId: 't1', ...dto };
    const tripSettingsService = {
      replaceSettings: jest.fn().mockResolvedValue(updated),
    };
    const controller = controllerWith({}, tripSettingsService);

    await expect(controller.replaceSettings('t1', dto)).resolves.toEqual(
      updated,
    );
    expect(tripSettingsService.replaceSettings).toHaveBeenCalledWith('t1', dto);
  });
});
