import { expect, tap } from '@git.zone/tstest/tapbundle';
import { PrusaLinkMapper, type IPrusaLinkRawData, type IPrusaLinkSnapshot } from '../../ts/integrations/prusalink/index.js';

const rawData: Partial<IPrusaLinkRawData> = {
  version: {
    api: '2.0.0',
    version: '5.1.0',
    printer: 'Original Prusa MK4',
    text: 'MK4 Printer',
    firmware: '6.0.1',
    sdk: null,
    hostname: 'mk4',
  },
  info: {
    name: 'Workshop MK4',
    serial: 'CZPX123456',
    hostname: 'mk4',
    location: 'Workshop',
    mmu: true,
    nozzle_diameter: 0.4,
    active_camera: true,
  },
  status: {
    printer: {
      state: 'PRINTING',
      temp_nozzle: 215.4,
      target_nozzle: 215,
      temp_bed: 60.2,
      target_bed: 60,
      axis_z: 3.2,
      speed: 95,
      flow: 98,
      fan_hotend: 4100,
      fan_print: 3200,
      status_printer: { ok: true, message: 'Printing' },
    },
  },
  legacyStatus: {
    telemetry: { material: 'PETG' },
  },
  job: {
    id: 7,
    state: 'PRINTING',
    progress: 42,
    time_printing: 600,
    time_remaining: 900,
    serial_print: false,
    file: {
      name: 'part.gcode',
      display_name: 'Part.gcode',
      path: '/usb/part.gcode',
      display_path: 'USB/Part.gcode',
      size: 1024,
      refs: { thumbnail: '/thumb/part.png', download: '/api/v1/files/usb/part.gcode' },
    },
  },
};

tap.test('maps PrusaLink raw API data to printer, job, temperature, progress, and button entities', async () => {
  const snapshot = PrusaLinkMapper.toSnapshot({ config: { host: 'mk4.local', name: 'Workshop MK4' }, rawData, online: true, source: 'manual' });
  const devices = PrusaLinkMapper.toDevices(snapshot);
  const entities = PrusaLinkMapper.toEntities(snapshot);

  expect(snapshot.printer.serialNumber).toEqual('CZPX123456');
  expect(snapshot.printer.model).toEqual('Original Prusa MK4');
  expect(snapshot.telemetry.state).toEqual('printing');
  expect(snapshot.telemetry.material).toEqual('PETG');
  expect(snapshot.job.filename).toEqual('Part.gcode');
  expect(snapshot.job.thumbnailPath).toEqual('/thumb/part.png');
  expect(devices[0].id).toEqual('prusalink.printer.czpx123456');
  expect(devices[0].metadata?.thumbnailPath).toEqual('/thumb/part.png');
  expect(entities.find((entityArg) => entityArg.attributes?.key === 'printer_state')?.state).toEqual('printing');
  expect(entities.find((entityArg) => entityArg.attributes?.key === 'nozzle_temperature')?.state).toEqual(215.4);
  expect(entities.find((entityArg) => entityArg.attributes?.key === 'heatbed_temperature')?.state).toEqual(60.2);
  expect(entities.find((entityArg) => entityArg.attributes?.key === 'progress')?.state).toEqual(42);
  expect(entities.find((entityArg) => entityArg.attributes?.key === 'filename')?.attributes?.thumbnailPath).toEqual('/thumb/part.png');
  expect(entities.find((entityArg) => entityArg.attributes?.key === 'mmu')?.state).toEqual('on');
  expect(entities.find((entityArg) => entityArg.id === 'button.workshop_mk4_pause_job')?.available).toBeTrue();
  expect(entities.find((entityArg) => entityArg.id === 'button.workshop_mk4_resume_job')?.available).toBeFalse();
});

tap.test('does not invent job sensors or available controls for idle snapshots', async () => {
  const idleSnapshot: IPrusaLinkSnapshot = PrusaLinkMapper.toSnapshot({
    config: { name: 'Idle MK4' },
    rawData: {
      status: { printer: { state: 'IDLE' } },
      job: {},
    },
    online: true,
    source: 'manual',
  });
  const entities = PrusaLinkMapper.toEntities(idleSnapshot);

  expect(entities.find((entityArg) => entityArg.attributes?.key === 'printer_state')?.state).toEqual('idle');
  expect(entities.some((entityArg) => entityArg.attributes?.key === 'progress')).toBeFalse();
  expect(entities.some((entityArg) => entityArg.attributes?.key === 'filename')).toBeFalse();
  expect(entities.find((entityArg) => entityArg.id === 'button.idle_mk4_pause_job')?.available).toBeFalse();
  expect(entities.find((entityArg) => entityArg.id === 'button.idle_mk4_cancel_job')?.available).toBeFalse();
});

tap.test('maps Home Assistant style button services to safe command shapes', async () => {
  const snapshot = PrusaLinkMapper.toSnapshot({ config: { host: 'mk4.local' }, rawData, online: true, source: 'manual' });
  const pause = PrusaLinkMapper.commandForService(snapshot, { domain: 'button', service: 'press', target: { entityId: 'button.workshop_mk4_pause_job' } });
  const cancel = PrusaLinkMapper.commandForService(snapshot, { domain: 'prusalink', service: 'cancel_job', target: {} });
  const restart = PrusaLinkMapper.commandForService(snapshot, { domain: 'prusalink', service: 'restart_job', target: {}, data: { job_id: 7 } });

  expect(pause?.method).toEqual('PUT');
  expect(pause?.path).toEqual('/api/v1/job/7/pause');
  expect(cancel?.method).toEqual('DELETE');
  expect(cancel?.path).toEqual('/api/v1/job/7');
  expect(restart?.action).toEqual('restart');
  expect(restart?.path).toBeUndefined();
});

export default tap.start();
