import { expect, tap } from '@git.zone/tstest/tapbundle';
import { SqueezeboxClient, SqueezeboxIntegration, type ISqueezeboxRawCommandRequest, type ISqueezeboxSnapshot } from '../../ts/integrations/squeezebox/index.js';

const snapshot: ISqueezeboxSnapshot = {
  server: { id: 'lms-1', uuid: 'server-uuid-1', name: 'Home LMS', host: '192.168.1.40' },
  players: [{
    playerId: '00:04:20:aa:bb:01',
    name: 'Living Room',
    model: 'Squeezebox Radio',
    connected: true,
    power: true,
    mode: 'pause',
    volume: 20,
    syncGroup: ['00:04:20:aa:bb:02'],
  }, {
    playerId: '00:04:20:aa:bb:02',
    name: 'Kitchen',
    model: 'Squeezebox Touch',
    connected: true,
    power: true,
    mode: 'pause',
    volume: 30,
    syncGroup: ['00:04:20:aa:bb:01'],
  }],
  favorites: [{ id: 'fav-1', name: 'Jazz Radio', url: 'http://radio.example/stream.mp3', playable: true }],
  syncGroups: [{ id: 'sync-main', playerIds: ['00:04:20:aa:bb:01', '00:04:20:aa:bb:02'], leaderPlayerId: '00:04:20:aa:bb:01' }],
  online: true,
};

tap.test('models Squeezebox playback volume source and sync commands through an executor', async () => {
  const commands: ISqueezeboxRawCommandRequest[] = [];
  const runtime = await new SqueezeboxIntegration().setup({
    snapshot,
    commandExecutor: {
      execute: async (requestArg) => {
        commands.push(requestArg);
        return { id: requestArg.body?.id, result: {} };
      },
    },
  }, {});

  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: 'Jazz Radio' } });
  const join = await runtime.callService!({ domain: 'media_player', service: 'join', target: { entityId: 'media_player.living_room' }, data: { group_members: ['media_player.kitchen'] } });
  const unjoin = await runtime.callService!({ domain: 'media_player', service: 'unjoin', target: { entityId: 'media_player.kitchen' } });

  expect(play.success).toBeTrue();
  expect(volume.success).toBeTrue();
  expect(source.success).toBeTrue();
  expect(join.success).toBeTrue();
  expect(unjoin.success).toBeTrue();
  expect(commands.map((commandArg) => commandArg.command)).toEqual([
    ['play'],
    ['mixer', 'volume', '35'],
    ['playlist', 'play', 'http://radio.example/stream.mp3'],
    ['sync', '00:04:20:aa:bb:02'],
    ['sync', '-'],
  ]);
  expect(commands[0].playerId).toEqual('00:04:20:aa:bb:01');
  expect(commands[4].playerId).toEqual('00:04:20:aa:bb:02');
});

tap.test('does not report live command success for static snapshots without transport', async () => {
  const runtime = await new SqueezeboxIntegration().setup({ snapshot }, {});
  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 LMS JSON-RPC over HTTP for live commands', async () => {
  const originalFetch = globalThis.fetch;
  const calls: Array<{ url: string; body: ISqueezeboxRawCommandRequest['body']; authorization?: string }> = [];
  globalThis.fetch = (async (urlArg: URL | RequestInfo, initArg?: RequestInit) => {
    const headers = initArg?.headers as Record<string, string> | undefined;
    calls.push({ url: String(urlArg), body: JSON.parse(String(initArg?.body)), authorization: headers?.authorization });
    return new Response(JSON.stringify({ id: 1, method: 'slim.request', result: {} }), { status: 200, headers: { 'content-type': 'application/json' } });
  }) as typeof globalThis.fetch;

  try {
    await new SqueezeboxClient({ host: 'lms.local', username: 'user', password: 'pass' }).execute({ command: 'set_volume', playerId: '00:04:20:aa:bb:01', volumeLevel: 0.5 });
    expect(calls[0].url).toEqual('http://lms.local:9000/jsonrpc.js');
    expect(calls[0].body?.method).toEqual('slim.request');
    expect(calls[0].body?.params).toEqual(['00:04:20:aa:bb:01', ['mixer', 'volume', '50']]);
    expect(calls[0].authorization?.startsWith('Basic ')).toBeTrue();
  } finally {
    globalThis.fetch = originalFetch;
  }
});

export default tap.start();
