import { expect, tap } from '@git.zone/tstest/tapbundle';
import { OpenRGBMapper, type IOpenRGBSnapshot } from '../../ts/integrations/openrgb/index.js';

const snapshot: IOpenRGBSnapshot = {
  connected: true,
  host: '192.168.1.20',
  port: 6742,
  name: 'Gaming PC',
  protocolVersion: 4,
  controller: {
    id: 'gaming-pc',
    name: 'Gaming PC',
    host: '192.168.1.20',
    port: 6742,
    protocolVersion: 4,
  },
  devices: [
    {
      id: 0,
      name: 'Mainboard',
      typeName: 'motherboard',
      metadata: {
        vendor: 'ASRock',
        description: 'X570 RGB',
        version: '1.0',
        serial: 'ABC123',
        location: 'PCI',
      },
      activeMode: 1,
      modes: [
        { id: 0, name: 'Off', value: 0, flags: 0, colorMode: 0 },
        { id: 1, name: 'Direct', value: 1, flags: 1 << 5, colorMode: 1 },
        { id: 2, name: 'Static', value: 2, flags: 1 << 6, colorMode: 2, colors: [{ red: 255, green: 255, blue: 255 }] },
        { id: 3, name: 'Rainbow', value: 3, flags: 0, colorMode: 0 },
      ],
      colors: [
        { red: 128, green: 64, blue: 0 },
        { red: 128, green: 64, blue: 0 },
      ],
      leds: [
        { id: 0, name: 'LED 1', value: 0 },
        { id: 1, name: 'LED 2', value: 0 },
      ],
      zones: [
        {
          id: 0,
          name: 'Header',
          typeName: 'linear',
          numLeds: 2,
          colors: [
            { red: 0, green: 32, blue: 64 },
            { red: 0, green: 32, blue: 64 },
          ],
          leds: [
            { id: 0, name: 'Header LED 1', value: 0 },
            { id: 1, name: 'Header LED 2', value: 0 },
          ],
        },
      ],
      available: true,
    },
  ],
  profiles: ['Gaming', 'Work'],
  events: [],
};

tap.test('maps OpenRGB controller, devices, zones, lights, and effects', async () => {
  const devices = OpenRGBMapper.toDevices(snapshot);
  const entities = OpenRGBMapper.toEntities(snapshot);
  const light = entities.find((entityArg) => entityArg.id === 'light.mainboard');
  const zoneLight = entities.find((entityArg) => entityArg.id === 'light.mainboard_header');

  expect(devices.some((deviceArg) => deviceArg.id === 'openrgb.controller.gaming_pc')).toBeTrue();
  expect(devices.some((deviceArg) => deviceArg.id.startsWith('openrgb.device.'))).toBeTrue();
  expect(devices.some((deviceArg) => deviceArg.id.startsWith('openrgb.zone.'))).toBeTrue();
  expect(light?.state).toEqual('on');
  expect(light?.attributes?.brightness).toEqual(128);
  expect(light?.attributes?.rgbColor).toEqual([255, 128, 0]);
  expect(light?.attributes?.effect).toEqual('off');
  expect(light?.attributes?.effectList).toEqual(['off', 'rainbow']);
  expect(zoneLight?.attributes?.brightness).toEqual(64);
  expect(zoneLight?.attributes?.rgbColor).toEqual([0, 128, 255]);
  expect(entities.find((entityArg) => entityArg.id === 'select.gaming_pc_profile')?.attributes?.options).toEqual(['Gaming', 'Work']);
});

tap.test('models safe OpenRGB light commands for mode, color, brightness, and off', async () => {
  const effectCommand = OpenRGBMapper.commandForService(snapshot, {
    domain: 'light',
    service: 'turn_on',
    target: { entityId: 'light.mainboard' },
    data: { effect: 'Rainbow' },
  });
  const colorCommand = OpenRGBMapper.commandForService(snapshot, {
    domain: 'light',
    service: 'turn_on',
    target: { entityId: 'light.mainboard' },
    data: { rgb_color: [10, 20, 30], brightness: 128 },
  });
  const offCommand = OpenRGBMapper.commandForService(snapshot, {
    domain: 'light',
    service: 'turn_off',
    target: { entityId: 'light.mainboard' },
  });
  const zoneOffCommand = OpenRGBMapper.commandForService(snapshot, {
    domain: 'light',
    service: 'turn_off',
    target: { entityId: 'light.mainboard_header' },
  });

  const effectOperation = effectCommand?.operations[0];
  const colorOperation = colorCommand?.operations[0];
  const offOperation = offCommand?.operations[0];
  const zoneOffOperation = zoneOffCommand?.operations[0];
  if (effectOperation?.action !== 'setMode' || offOperation?.action !== 'setMode' || colorOperation?.action !== 'setColor' || zoneOffOperation?.action !== 'setColor') {
    throw new Error('OpenRGB command operations were not modeled with the expected action types.');
  }
  expect(effectOperation.modeName).toEqual('Rainbow');
  expect(colorOperation.rgb).toEqual({ red: 5, green: 10, blue: 15 });
  expect(offOperation.modeName).toEqual('Off');
  expect(zoneOffOperation.zoneIndex).toEqual(0);
  expect(zoneOffOperation.rgb).toEqual({ red: 0, green: 0, blue: 0 });
});

export default tap.start();
