import { MaintenanceService } from './maintenance.service';
import { MaintenanceStatus } from './entities/maintenance-schedule.entity';

/**
 * KM-based auto-scheduling: completing a maintenance with an odometer reading
 * creates the next SCHEDULED item at completedKm + intervalKm, matched on the
 * schedule's (type, serviceItem) interval. Re-completing must not duplicate.
 */
function makeService(opts: {
  before: Record<string, unknown> | null;
  after: Record<string, unknown> | null;
  interval: Record<string, unknown> | null;
}) {
  const saved: Array<Record<string, unknown>> = [];
  const service = Object.create(MaintenanceService.prototype) as Record<string, unknown>;
  service.scheduleRepository = {
    findOneBy: jest
      .fn()
      .mockResolvedValueOnce(opts.before)
      .mockResolvedValueOnce(opts.after),
    update: jest.fn(),
    create: jest.fn((v: Record<string, unknown>) => v),
    save: jest.fn(async (v: Record<string, unknown>) => {
      saved.push(v);
      return v;
    }),
  };
  service.intervalRepository = {
    getByVehicleAndType: jest.fn().mockResolvedValue(opts.interval),
  };
  service.dataSource = {
    getRepository: jest.fn().mockReturnValue({ update: jest.fn() }),
  };
  service.logger = { error: jest.fn() };
  return { service: service as unknown as MaintenanceService, saved };
}

const base = {
  id: 's-1',
  vehicleId: 'v-1',
  maintenanceType: 'PREVENTIVE',
  serviceItem: 'oil change',
  description: 'Oil and filter',
};

describe('MaintenanceService auto-next scheduling', () => {
  it('completing at 50,000 km with a 10,000 km interval schedules the next at 60,000', async () => {
    const { service, saved } = makeService({
      before: { ...base, status: MaintenanceStatus.SCHEDULED },
      after: { ...base, status: MaintenanceStatus.COMPLETED, odometerReading: 50000 },
      interval: { serviceItem: 'oil change', intervalKm: '10000.00', intervalDays: null, description: 'Oil and filter' },
    });

    await service.updateMaintenanceSchedule('s-1', {
      status: MaintenanceStatus.COMPLETED,
      odometerReading: 50000,
    });

    expect(saved).toHaveLength(1);
    expect(saved[0]).toMatchObject({
      vehicleId: 'v-1',
      serviceItem: 'oil change',
      nextDueKm: 60000,
      status: MaintenanceStatus.SCHEDULED,
    });
  });

  it('re-completing an already COMPLETED schedule does not duplicate the next one', async () => {
    const { service, saved } = makeService({
      before: { ...base, status: MaintenanceStatus.COMPLETED, odometerReading: 50000 },
      after: { ...base, status: MaintenanceStatus.COMPLETED, odometerReading: 50000 },
      interval: { serviceItem: 'oil change', intervalKm: '10000.00', intervalDays: null },
    });

    await service.updateMaintenanceSchedule('s-1', {
      status: MaintenanceStatus.COMPLETED,
      odometerReading: 50000,
    });

    expect(saved).toHaveLength(0);
  });

  it('a km + days interval produces ONE next schedule carrying both thresholds', async () => {
    const { service, saved } = makeService({
      before: { ...base, status: MaintenanceStatus.IN_PROGRESS },
      after: { ...base, status: MaintenanceStatus.COMPLETED, odometerReading: 20000 },
      interval: { serviceItem: 'oil change', intervalKm: '10000.00', intervalDays: 180 },
    });

    await service.updateMaintenanceSchedule('s-1', {
      status: MaintenanceStatus.COMPLETED,
      odometerReading: 20000,
    });

    expect(saved).toHaveLength(1);
    expect(saved[0].nextDueKm).toBe(30000);
    expect(saved[0].nextDueDate).toBeInstanceOf(Date);
  });
});
