import { expect, tap } from '@git.zone/tstest/tapbundle';
import { LinkplayClient, LinkplayIntegration, type ILinkplayRawCommandRequest, type ILinkplaySnapshot } from '../../ts/integrations/linkplay/index.js';

const snapshot: ILinkplaySnapshot = {
  online: true,
  source: 'snapshot',
  speakers: [{
    uuid: 'leader-uuid',
    name: 'Living Room',
    available: true,
    device: {
      uuid: 'leader-uuid',
      name: 'Living Room',
      host: '192.168.1.10',
      port: 80,
      protocol: 'http',
      manufacturer: 'Arylic',
      model: 'S50+',
      ethernetAddress: '192.168.1.10',
      playModeSupport: ['10', '41', '40'],
      maxPresets: 4,
    },
    player: { status: 'pause', playMode: '10', loopMode: '4', volume: 20, muted: false },
    sources: [{ mode: '10', name: 'Wifi', commandValue: 'wifi' }, { mode: '41', name: 'Bluetooth', commandValue: 'bluetooth' }],
    presets: [{ number: 1, name: 'Jazz' }, { number: 2, name: 'News' }, { number: 3, name: 'Rock' }, { number: 4, name: 'Kitchen' }],
  }, {
    uuid: 'follower-uuid',
    name: 'Kitchen',
    available: true,
    device: {
      uuid: 'follower-uuid',
      name: 'Kitchen',
      host: '192.168.1.11',
      port: 80,
      protocol: 'http',
      manufacturer: 'Arylic',
      model: 'Up2Stream Mini',
      ethernetAddress: '192.168.1.11',
      playModeSupport: ['10', '41'],
      maxPresets: 4,
    },
    player: { status: 'pause', playMode: '99', loopMode: '4', volume: 30, muted: false },
  }],
  multirooms: [{ id: 'downstairs', leaderUuid: 'leader-uuid', followerUuids: ['follower-uuid'] }],
};

tap.test('models LinkPlay media, preset and multiroom commands through an executor', async () => {
  const commands: ILinkplayRawCommandRequest[] = [];
  const runtime = await new LinkplayIntegration().setup({
    snapshot,
    commandExecutor: {
      execute: async (requestArg) => {
        commands.push(requestArg);
        return 'OK';
      },
    },
  }, {});

  const play = await runtime.callService!({ domain: 'media_player', service: 'media_play', target: { entityId: 'media_player.living_room' } });
  const volume = await runtime.callService!({ domain: 'media_player', service: 'volume_set', target: { entityId: 'media_player.living_room' }, data: { volume_level: 0.35 } });
  const source = await runtime.callService!({ domain: 'media_player', service: 'select_source', target: { entityId: 'media_player.living_room' }, data: { source: 'Bluetooth' } });
  const preset = await runtime.callService!({ domain: 'linkplay', service: 'play_preset', target: { entityId: 'media_player.living_room' }, data: { preset_number: 2 } });
  const join = await runtime.callService!({ domain: 'media_player', service: 'join', target: { entityId: 'media_player.living_room' }, data: { group_members: ['media_player.kitchen'] } });
  const groupVolume = await runtime.callService!({ domain: 'linkplay', service: 'group_volume_set', target: { entityId: 'media_player.living_room' }, data: { volume_level: 0.5 } });

  expect(play.success).toBeTrue();
  expect(volume.success).toBeTrue();
  expect(source.success).toBeTrue();
  expect(preset.success).toBeTrue();
  expect(join.success).toBeTrue();
  expect(groupVolume.success).toBeTrue();
  expect(commands.map((commandArg) => commandArg.command)).toEqual([
    'setPlayerCmd:resume',
    'setPlayerCmd:vol:35',
    'setPlayerCmd:switchmode:bluetooth',
    'MCUKeyShortClick:2',
    'ConnectMasterAp:JoinGroupMaster:eth192.168.1.10:wifi0.0.0.0',
    'setPlayerCmd:slave_vol:50',
  ]);
  expect(commands[4].host).toEqual('192.168.1.11');
  expect(commands[5].host).toEqual('192.168.1.10');
});

tap.test('does not report live command success for static snapshots without transport', async () => {
  const staticSnapshot: ILinkplaySnapshot = {
    ...snapshot,
    speakers: snapshot.speakers.map((speakerArg) => ({
      ...speakerArg,
      device: { ...speakerArg.device, host: undefined },
    })),
  };
  const runtime = await new LinkplayIntegration().setup({ snapshot: staticSnapshot }, {});
  const result = await runtime.callService!({ domain: 'media_player', service: 'media_play', target: { entityId: 'media_player.living_room' } });
  expect(result.success).toBeFalse();
  expect(result.error?.includes('config.host or commandExecutor')).toBeTrue();
});

tap.test('uses native LinkPlay HTTP API for live commands', async () => {
  const originalFetch = globalThis.fetch;
  const calls: URL[] = [];
  globalThis.fetch = (async (urlArg: URL | RequestInfo, initArg?: RequestInit) => {
    void initArg;
    calls.push(new URL(String(urlArg)));
    return new Response('OK', { status: 200 });
  }) as typeof globalThis.fetch;

  try {
    const client = new LinkplayClient({
      host: 'speaker.local',
      snapshot: {
        ...snapshot,
        speakers: [{ ...snapshot.speakers[0], device: { ...snapshot.speakers[0].device, host: undefined } }],
        multirooms: [],
      },
    });
    await client.execute({ command: 'set_volume', speakerUuid: 'leader-uuid', volumeLevel: 0.4 });
    expect(calls[0].toString()).toEqual('http://speaker.local/httpapi.asp?command=setPlayerCmd%3Avol%3A40');
    expect(calls[0].searchParams.get('command')).toEqual('setPlayerCmd:vol:40');
  } finally {
    globalThis.fetch = originalFetch;
  }
});

export default tap.start();
