import { expect, tap } from '@git.zone/tstest/tapbundle';
import { Go2rtcClient, Go2rtcIntegration, type IGo2rtcRawCommandRequest, type IGo2rtcSnapshot } from '../../ts/integrations/go2rtc/index.js';

const staticSnapshot: IGo2rtcSnapshot = {
  id: 'static-go2rtc',
  name: 'Static go2rtc',
  connected: true,
  configured: true,
  source: 'snapshot',
  schemes: ['rtsp', 'webrtc'],
  endpoints: {},
  streams: [{
    id: 'front_door',
    name: 'front_door',
    sourceUrls: ['rtsp://camera.local/front'],
    producerCount: 1,
    consumerCount: 0,
    producers: [{ url: 'rtsp://camera.local/front' }],
    consumers: [],
    online: true,
    configured: true,
  }],
  cameras: [],
  sensors: [],
};

tap.test('builds a live go2rtc snapshot through a command executor', async () => {
  const requests: IGo2rtcRawCommandRequest[] = [];
  const client = new Go2rtcClient({
    url: 'http://go2rtc.local:1984',
    commandExecutor: {
      execute: async (requestArg) => {
        requests.push(requestArg);
        if (requestArg.path === '/api') {
          return { data: { version: '1.9.14', host: 'go2rtc.local:1984', rtsp: { listen: ':8554', default_query: 'video&audio' } } };
        }
        if (requestArg.path === '/api/schemes') {
          return { data: ['rtsp', 'ffmpeg', 'webrtc'] };
        }
        return {
          data: {
            front_door: {
              producers: [{ url: 'rtsp://camera.local/front', tracks: [{ codec: 'h264', media: 'video' }] }],
              consumers: [],
            },
          },
        };
      },
    },
  });

  const snapshot = await client.getSnapshot();
  expect(snapshot.connected).toBeTrue();
  expect(snapshot.serverInfo?.version).toEqual('1.9.14');
  expect(snapshot.streams[0].name).toEqual('front_door');
  expect(snapshot.cameras[0].endpoints.rtspUrl).toEqual('rtsp://go2rtc.local:8554/front_door?video&audio');
  expect(requests.map((requestArg) => requestArg.path)).toEqual(['/api', '/api/schemes', '/api/streams']);
});

tap.test('executes snapshot and stream mutation commands only through transport', async () => {
  const requests: IGo2rtcRawCommandRequest[] = [];
  const client = new Go2rtcClient({
    snapshot: staticSnapshot,
    commandExecutor: {
      execute: async (requestArg) => {
        requests.push(requestArg);
        if (requestArg.expect === 'image') {
          return { contentType: 'image/jpeg', body: new Uint8Array([1, 2, 3]) };
        }
        return { ok: true };
      },
    },
  });

  const image = await client.execute({ type: 'snapshot_image', service: 'snapshot', streamId: 'front_door', snapshot: { streamId: 'front_door' } });
  const add = await client.execute({ type: 'add_stream', service: 'add_stream', streamMutation: { name: 'garage', src: 'rtsp://camera.local/garage' } });

  expect((image as { contentType?: string }).contentType).toEqual('image/jpeg');
  expect((image as { dataBase64?: string }).dataBase64).toEqual('AQID');
  expect((add as { ok?: boolean }).ok).toBeTrue();
  expect(requests[0].path).toEqual('/api/frame.jpeg');
  expect(requests[1].method).toEqual('PUT');
  expect(requests[1].query).toEqual({ name: 'garage', src: 'rtsp://camera.local/garage' });
});

tap.test('does not report live HTTP command success for static snapshots without transport', async () => {
  const runtime = await new Go2rtcIntegration().setup({ snapshot: staticSnapshot }, {});
  const result = await runtime.callService!({
    domain: 'go2rtc',
    service: 'add_stream',
    target: {},
    data: { name: 'garage', src: 'rtsp://camera.local/garage' },
  });
  const refresh = await runtime.callService!({ domain: 'go2rtc', service: 'refresh', target: {} });

  expect(result.success).toBeFalse();
  expect(result.error?.includes('config.url, config.host, or commandExecutor')).toBeTrue();
  expect(refresh.success).toBeFalse();
  expect(refresh.error?.includes('config.url, config.host, or commandExecutor')).toBeTrue();
});

export default tap.start();
