import { expect, tap } from '@git.zone/tstest/tapbundle';
import { ForkedDaapdClient, ForkedDaapdIntegration, type IForkedDaapdRawCommandRequest, type IForkedDaapdSnapshot } from '../../ts/integrations/forked_daapd/index.js';

const snapshot: IForkedDaapdSnapshot = {
  online: true,
  source: 'snapshot',
  server: { id: 'Living Room', name: 'Living Room', host: 'living-room.local', port: 3689, protocol: 'http', libraryName: 'Living Room', websocketPort: 3688 },
  player: { state: 'pause', repeat: 'off', consume: false, shuffle: false, volume: 20, item_id: 0, item_length_ms: 0, item_progress_ms: 0 },
  queue: { version: 0, count: 0, items: [] },
  outputs: [{ id: '0', name: 'Computer', type: 'ALSA', selected: true, volume: 20 }],
  library: { pipes: [], playlists: [{ name: 'Favorites', uri: 'library:playlist:1' }] },
};

tap.test('models OwnTone media and output commands through an executor', async () => {
  const requests: IForkedDaapdRawCommandRequest[] = [];
  const runtime = await new ForkedDaapdIntegration().setup({
    snapshot,
    commandExecutor: {
      execute: async (requestArg) => {
        requests.push(requestArg);
        return { status: requestArg.method === 'POST' ? 200 : 204 };
      },
    },
  }, {});

  const play = await runtime.callService!({ domain: 'media_player', service: 'media_play', target: { entityId: 'media_player.living_room_owntone' } });
  const volume = await runtime.callService!({ domain: 'media_player', service: 'volume_set', target: { entityId: 'media_player.living_room_owntone' }, data: { volume_level: 0.35 } });
  const source = await runtime.callService!({ domain: 'media_player', service: 'select_source', target: { entityId: 'media_player.living_room_owntone' }, data: { source: 'Favorites (playlist)' } });
  const outputOff = await runtime.callService!({ domain: 'media_player', service: 'turn_off', target: { entityId: 'media_player.living_room_owntone_computer' } });

  expect(play.success).toBeTrue();
  expect(volume.success).toBeTrue();
  expect(source.success).toBeTrue();
  expect(outputOff.success).toBeTrue();
  expect(requests.map((requestArg) => `${requestArg.method} ${requestArg.endpoint}`)).toEqual([
    'PUT player/play',
    'PUT player/volume',
    'POST queue/items/add',
    'PUT outputs/0',
  ]);
  expect(requests[1].params?.volume).toEqual(35);
  expect(requests[2].params?.uris).toEqual('library:playlist:1');
  expect(requests[3].body).toEqual({ selected: false });
});

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

tap.test('uses native OwnTone HTTP API for live commands', async () => {
  const originalFetch = globalThis.fetch;
  const calls: Array<{ url: URL; init?: RequestInit }> = [];
  globalThis.fetch = (async (urlArg: URL | RequestInfo, initArg?: RequestInit) => {
    calls.push({ url: new URL(String(urlArg)), init: initArg });
    return new Response(null, { status: 204 });
  }) as typeof globalThis.fetch;

  try {
    const client = new ForkedDaapdClient({ host: 'owntone.local', port: 3689, password: 'secret' });
    await client.execute({ command: 'set_volume', volumeLevel: 0.4 });
    expect(calls[0].url.toString()).toEqual('http://owntone.local:3689/api/player/volume?volume=40');
    expect(calls[0].init?.method).toEqual('PUT');
    expect((calls[0].init?.headers as Record<string, string>).Authorization.startsWith('Basic ')).toBeTrue();
  } finally {
    globalThis.fetch = originalFetch;
  }
});

export default tap.start();
