import { BadRequestException } from '@nestjs/common';

import { VehiclesService } from './vehicles.service';

// A trailer plate only exists on a configuration that pulls a trailer. A rigid
// truck (Casoni) has none, so registering or editing one into a trailer plate
// must be refused server-side — the form hiding the field is not enforcement.
describe('VehiclesService trailer plate guard', () => {
  const CASONI = { code: 'CASONI', name: 'Casoni (rigid, no trailer)', hasTrailer: false, capacityTons: 30 };
  const ARTIC = { code: 'TRUCK', name: 'Truck', hasTrailer: true, capacityTons: 40 };

  const makeService = (findOne: jest.Mock, truckType: unknown) => {
    const save = jest.fn(async (x) => x);
    const svc = new VehiclesService(
      { findOne, create: jest.fn((x) => x), save } as any,
      { record: jest.fn() } as any,
      { findById: jest.fn(async () => truckType) } as any,
    );
    return { svc, save };
  };

  it('rejects creating a rigid truck that carries a trailer plate', async () => {
    const findOne = jest.fn().mockResolvedValueOnce(null); // plate is free
    const { svc } = makeService(findOne, CASONI);
    await expect(
      svc.create({ plateNumber: 'ET-9875', truckTypeId: 'tt-casoni', trailerPlateNo: 'ET-1234' } as any),
    ).rejects.toThrow(BadRequestException);
  });

  it('accepts a rigid truck with no trailer plate, and takes capacity from the type', async () => {
    const findOne = jest.fn().mockResolvedValueOnce(null);
    const { svc } = makeService(findOne, CASONI);
    const saved = await svc.create({ plateNumber: 'ET-9875', truckTypeId: 'tt-casoni' } as any);
    expect(saved.capacity).toBe(30);
    // Denormalised code is what truck-detention billing groups on.
    expect(saved.vehicleType).toBe('CASONI');
  });

  it('keeps an explicit capacity over the type default', async () => {
    const findOne = jest.fn().mockResolvedValueOnce(null);
    const { svc } = makeService(findOne, CASONI);
    const saved = await svc.create({
      plateNumber: 'ET-9875',
      truckTypeId: 'tt-casoni',
      capacity: 25,
    } as any);
    expect(saved.capacity).toBe(25);
  });

  it('allows a trailer plate on an articulated type', async () => {
    const findOne = jest.fn().mockResolvedValueOnce(null);
    const { svc } = makeService(findOne, ARTIC);
    await expect(
      svc.create({ plateNumber: 'ET-9875', truckTypeId: 'tt-truck', trailerPlateNo: 'ET-1234' } as any),
    ).resolves.toBeDefined();
  });

  // The regression that motivated validating the RESULT rather than the patch:
  // switching type alone leaves the stored trailer plate behind.
  it('rejects switching an existing truck to a rigid type while its trailer plate stands', async () => {
    const findOne = jest
      .fn()
      .mockResolvedValueOnce({ id: 'v1', plateNumber: 'ET-9875', trailerPlateNo: 'ET-1234' });
    const { svc } = makeService(findOne, CASONI);
    await expect(svc.update('v1', { truckTypeId: 'tt-casoni' } as any)).rejects.toThrow(
      BadRequestException,
    );
  });

  it('allows the switch when the trailer plate is cleared in the same edit', async () => {
    const findOne = jest
      .fn()
      .mockResolvedValueOnce({ id: 'v1', plateNumber: 'ET-9875', trailerPlateNo: 'ET-1234' });
    const { svc } = makeService(findOne, CASONI);
    const saved = await svc.update('v1', {
      truckTypeId: 'tt-casoni',
      trailerPlateNo: null,
    } as any);
    expect(saved.vehicleType).toBe('CASONI');
  });
});
