import { expect, tap } from '@git.zone/tstest/tapbundle';
import { ChannelsClient, ChannelsIntegration, HomeAssistantChannelsIntegration, type IChannelsCommand } from '../../ts/integrations/channels/index.js';

tap.test('fetches Channels HTTP API snapshots and sends media commands', async () => {
  const originalFetch = globalThis.fetch;
  const requests: Array<{ url: string; method: string }> = [];
  globalThis.fetch = (async (inputArg: RequestInfo | URL, initArg?: RequestInit) => {
    const url = typeof inputArg === 'string' ? inputArg : inputArg instanceof URL ? inputArg.toString() : inputArg.url;
    const method = initArg?.method || 'GET';
    requests.push({ url, method });
    const parsed = new URL(url);

    if (method === 'GET' && parsed.pathname === '/api/status') {
      return jsonResponse({
        status: 'playing',
        muted: false,
        channel: { number: '35.1', name: 'Fox-HD', image_url: 'http://images.example/channel.png' },
        now_playing: { title: 'The Mick' },
      });
    }
    if (method === 'GET' && parsed.pathname === '/api/favorite_channels') {
      return jsonResponse([{ number: '35.1', name: 'Fox-HD' }]);
    }
    if (method === 'POST' && parsed.pathname === '/api/pause') {
      return jsonResponse({ status: 'paused', muted: false });
    }
    if (method === 'POST' && parsed.pathname === '/api/play/channel/35.1') {
      return jsonResponse({ status: 'playing', muted: false, channel: { number: '35.1', name: 'Fox-HD' } });
    }
    return jsonResponse({ status: 'error' }, 404);
  }) as typeof fetch;

  try {
    const client = new ChannelsClient({ host: '127.0.0.1:57000', timeoutMs: 1000 });
    const snapshot = await client.getSnapshot();
    expect(snapshot.online).toBeTrue();
    expect(snapshot.status.status).toEqual('playing');
    expect(snapshot.favoriteChannels[0].name).toEqual('Fox-HD');

    await client.pause();
    await client.playChannel('35.1');
    expect(requests.some((requestArg) => requestArg.method === 'POST' && requestArg.url.endsWith('/api/pause'))).toBeTrue();
    expect(requests.some((requestArg) => requestArg.method === 'POST' && requestArg.url.endsWith('/api/play/channel/35.1'))).toBeTrue();
  } finally {
    globalThis.fetch = originalFetch;
  }
});

tap.test('does not fake media control success without host or executor', async () => {
  const runtime = await new ChannelsIntegration().setup({
    name: 'Snapshot Channels',
    status: { status: 'stopped', muted: false },
    favoriteChannels: [{ number: '35.1', name: 'Fox-HD' }],
  }, {});

  const result = await runtime.callService?.({
    domain: 'media_player',
    service: 'media_play',
    target: { entityId: 'media_player.snapshot_channels' },
    data: {},
  });

  expect(result?.success).toBeFalse();
  expect(result?.error || '').toInclude('require config.host or commandExecutor');
  await runtime.destroy();
});

tap.test('delegates Channels commands to an injected executor and preserves alias class', async () => {
  let command: IChannelsCommand | undefined;
  const integration = new ChannelsIntegration();
  const alias = new HomeAssistantChannelsIntegration();
  expect(alias instanceof ChannelsIntegration).toBeTrue();

  const runtime = await integration.setup({
    name: 'Executor Channels',
    status: { status: 'stopped', muted: false },
    commandExecutor: async (commandArg) => {
      command = commandArg;
      return { success: true, transmitted: true, status: { status: 'playing', muted: false } };
    },
  }, {});

  const result = await runtime.callService?.({
    domain: 'media_player',
    service: 'media_play',
    target: { entityId: 'media_player.executor_channels' },
    data: {},
  });

  expect(result?.success).toBeTrue();
  expect(command?.type).toEqual('resume');
  expect(command?.path).toEqual('/api/resume');

  const snapshotResult = await runtime.callService?.({ domain: 'channels', service: 'snapshot', target: {}, data: {} });
  const snapshot = snapshotResult?.data as { status?: { status?: string } } | undefined;
  expect(snapshot?.status?.status).toEqual('playing');
  await runtime.destroy();
});

const jsonResponse = (valueArg: unknown, statusArg = 200): Response => {
  return new Response(JSON.stringify(valueArg), {
    status: statusArg,
    headers: { 'content-type': 'application/json' },
  });
};

export default tap.start();
