import { ContractRateScheduleBuilder } from './contract-rate-schedule.builder';
import { Rate } from '../modules/rule-engine/entities/rate.entity';

/** Minimal Rate factory for the builder unit tests. */
function rate(partial: Partial<Rate>): Rate {
  return {
    trigger: 'ALWAYS',
    appliesTo: 'CONTAINER',
    tradeDirection: 'IMPORT',
    rateType: 'CONTAINER_IMPORT',
    currency: 'USD',
    rateValue: 200,
    rateUnit: 'PER_CONTAINER',
    ...partial,
  } as Rate;
}

describe('ContractRateScheduleBuilder', () => {
  const LIVE: Rate[] = [
    rate({
      appliesTo: 'CONTAINER',
      tradeDirection: 'IMPORT',
      rateType: 'CONTAINER_IMPORT',
      rateValue: 200,
      rateUnit: 'PER_CONTAINER',
      originYard: { label: 'Negad' } as never,
      destinationYard: { label: 'Mojo Dry Port' } as never,
      containerType: { label: '40ft GP' } as never,
    }),
    rate({
      appliesTo: 'CONTAINER',
      tradeDirection: 'EXPORT', // wrong direction — must be filtered out for import
      rateType: 'CONTAINER_EXPORT',
      rateValue: 819,
      originYard: { label: 'GMP' } as never,
      destinationYard: { label: 'SGTD' } as never,
    }),
    rate({
      appliesTo: 'BULK', // wrong freight — filtered out for a container contract
      tradeDirection: 'IMPORT',
      rateType: 'BULK_IMPORT',
      rateUnit: 'PER_WAGON',
      rateValue: 100,
    }),
    rate({
      appliesTo: 'FIRST_MILE',
      trigger: 'ALWAYS',
      tradeDirection: null,
      rateUnit: 'PER_CONTAINER',
      rateValue: 50,
    }),
    rate({
      appliesTo: 'OTHER',
      trigger: 'CUSTOMS_CLEARANCE',
      tradeDirection: null,
      rateType: 'CUSTOMS_CLEARANCE',
      rateUnit: 'FLAT',
      rateValue: 120,
    }),
  ];

  const build = (dir: 'IMP' | 'EXP' | 'DOM', freight: 'CON' | 'BULK') => {
    const service = { findLiveRatesDetailed: jest.fn().mockResolvedValue(LIVE) };
    return new ContractRateScheduleBuilder(service as never).build(dir, freight);
  };

  it('shows only import container lanes for an import container contract', async () => {
    const s = await build('IMP', 'CON');
    expect(s.freightLanes).toHaveLength(1);
    expect(s.freightLanes[0]).toMatchObject({
      route: 'Negad → Mojo Dry Port',
      cargo: '40ft GP',
      currency: 'USD',
      amount: '200',
      unit: 'per container',
    });
  });

  it('always lists route-agnostic services and surcharges', async () => {
    const s = await build('IMP', 'CON');
    expect(s.additionalServices).toHaveLength(1);
    expect(s.additionalServices[0].route).toBe('First-mile pickup by truck');
    expect(s.surcharges).toHaveLength(1);
    expect(s.surcharges[0].route).toBe('Customs clearance service');
  });

  it('excludes container lanes from a bulk contract', async () => {
    const s = await build('IMP', 'BULK');
    expect(s.freightLanes).toHaveLength(1);
    expect(s.freightLanes[0]).toMatchObject({ amount: '100', unit: 'per wagon' });
  });

  it('flags an empty schedule when nothing priced matches', async () => {
    const service = { findLiveRatesDetailed: jest.fn().mockResolvedValue([]) };
    const s = await new ContractRateScheduleBuilder(service as never).build('DOM', 'CON');
    expect(s.isEmpty).toBe(true);
  });
});
