import { BadRequestException } from '@nestjs/common';
import { BookingTransitionService } from './booking-transition.service';

/**
 * Operation-request review for general-contract drawdown orders:
 *  - ACCEPT a train order → FULLY_EXECUTED and enqueued into the batch pool.
 *  - ACCEPT a road order  → ROAD_DISPATCH_PENDING, NOT enqueued.
 *  - REQUEST_CHANGES requires a note → OPERATION_CHANGES_REQUESTED.
 *  - ADJUST_PRICE sets the adjusted total → OPERATION_PRICE_PENDING_CONFIRM.
 */
describe('BookingTransitionService — operation review', () => {
  function makeService(serviceTypeCode: string) {
    const booking = {
      id: 'b-1',
      status: 'OPERATION_REQUEST_PENDING',
      originYardId: 'o-1',
      destinationYardId: 'd-1',
      scheduledDate: new Date('2026-07-01T00:00:00.000Z'),
      serviceType: { code: serviceTypeCode },
    };
    const bookingsRepository = {
      update: jest.fn().mockResolvedValue({ id: 'b-1' }),
      createReviewNote: jest.fn().mockResolvedValue(undefined),
    };
    const bookingsService = {
      findById: jest.fn().mockResolvedValue(booking),
    };
    const bookingBatchService = {
      enqueueRouteDayProcessing: jest.fn(),
    };

    const service = new BookingTransitionService(
      bookingsRepository as never,
      {} as never, // ruleEngineService
      {} as never, // pricingService
      {} as never, // contractService
      {} as never, // filesService
      {} as never, // fileUploadSettingsService
      bookingBatchService as never,
      bookingsService as never,
    );
    return { service, bookingsRepository, bookingBatchService };
  }

  it('ACCEPT of a train order → FULLY_EXECUTED and enqueues the batch pool', async () => {
    const { service, bookingsRepository, bookingBatchService } =
      makeService('RAIL_CONTAINER');
    await service.reviewOperationRequest('b-1', 'ACCEPT', 'staff-1');
    expect(bookingsRepository.update).toHaveBeenCalledWith(
      'b-1',
      expect.objectContaining({ status: 'FULLY_EXECUTED' }),
    );
    expect(bookingBatchService.enqueueRouteDayProcessing).toHaveBeenCalledTimes(1);
  });

  it('ACCEPT of a road order → ROAD_DISPATCH_PENDING and does NOT enqueue', async () => {
    const { service, bookingsRepository, bookingBatchService } =
      makeService('ROAD_CONTAINER');
    await service.reviewOperationRequest('b-1', 'ACCEPT', 'staff-1');
    expect(bookingsRepository.update).toHaveBeenCalledWith(
      'b-1',
      expect.objectContaining({ status: 'ROAD_DISPATCH_PENDING' }),
    );
    expect(bookingBatchService.enqueueRouteDayProcessing).not.toHaveBeenCalled();
  });

  it('REQUEST_CHANGES requires a note → OPERATION_CHANGES_REQUESTED', async () => {
    const { service, bookingsRepository } = makeService('RAIL_CONTAINER');
    await expect(
      service.reviewOperationRequest('b-1', 'REQUEST_CHANGES', 'staff-1', {}),
    ).rejects.toBeInstanceOf(BadRequestException);

    await service.reviewOperationRequest('b-1', 'REQUEST_CHANGES', 'staff-1', {
      note: 'Fix the schedule',
    });
    expect(bookingsRepository.update).toHaveBeenCalledWith(
      'b-1',
      expect.objectContaining({ status: 'OPERATION_CHANGES_REQUESTED' }),
    );
  });

  it('ADJUST_PRICE sets the adjusted total → OPERATION_PRICE_PENDING_CONFIRM', async () => {
    const { service, bookingsRepository } = makeService('RAIL_CONTAINER');
    await service.reviewOperationRequest('b-1', 'ADJUST_PRICE', 'staff-1', {
      amount: 1500,
    });
    expect(bookingsRepository.update).toHaveBeenCalledWith(
      'b-1',
      expect.objectContaining({
        adjustedTotalAmount: 1500,
        status: 'OPERATION_PRICE_PENDING_CONFIRM',
      }),
    );
  });
});
