import { expect, tap } from '@git.zone/tstest/tapbundle';
import { FoscamClient, FoscamIntegration, HomeAssistantFoscamIntegration } from '../../ts/integrations/foscam/index.js';

tap.test('fetches live Foscam snapshots and only reports commands after CGI success', async () => {
  const originalFetch = globalThis.fetch;
  const requests: string[] = [];
  globalThis.fetch = (async (inputArg: RequestInfo | URL) => {
    const url = typeof inputArg === 'string' ? inputArg : inputArg instanceof URL ? inputArg.toString() : inputArg.url;
    requests.push(url);
    const parsed = new URL(url);
    const cmd = parsed.searchParams.get('cmd');

    if (cmd === 'snapPicture2') {
      return new Response(new Uint8Array([0xff, 0xd8, 0xff]), { headers: { 'content-type': 'image/jpeg' } });
    }
    if (cmd === 'getProductAllInfo') {
      return xmlResponse({ model: '7002', productName: 'FI9821W', reserve4: '384' });
    }
    if (cmd === 'getDevInfo') {
      return xmlResponse({ devName: 'Porch Foscam', productName: 'FI9821W', firmwareVer: '1.2.3', hardwareVer: '4.5.6' });
    }
    if (cmd === 'getPortInfo') {
      return xmlResponse({ rtspPort: '554' });
    }
    if (cmd === 'getInfraLedConfig') {
      return xmlResponse({ mode: '1' });
    }
    if (cmd === 'getMirrorAndFlipSetting') {
      return xmlResponse({ isFlip: '0', isMirror: '1' });
    }
    if (cmd === 'getAlexaState') {
      return xmlResponse({ state: '0' });
    }
    if (cmd === 'getWhiteLightBrightness') {
      return xmlResponse({ enable: '1' });
    }
    if (cmd === 'getSirenConfig') {
      return xmlResponse({ sirenEnable: '0' });
    }
    if (cmd === 'getAudioVolume') {
      return xmlResponse({ volume: '20' });
    }
    if (cmd === 'getSpeakVolume') {
      return xmlResponse({ SpeakVolume: '35' });
    }
    if (cmd === 'getVoiceEnableState') {
      return xmlResponse({ isEnable: '1' });
    }
    if (cmd === 'getLedEnableState') {
      return xmlResponse({ isEnable: '1' });
    }
    if (cmd === 'getSWCapabilities') {
      return xmlResponse({ swCapabilities1: '32', swCapabilities2: '896' });
    }
    if (cmd === 'getMotionDetectConfig') {
      return xmlResponse({ isEnable: '1', petEnable: '1', carEnable: '0', humanEnable: '1' });
    }
    if (cmd === 'getWdrMode') {
      return xmlResponse({ mode: '1' });
    }
    if (cmd === 'getHdrMode') {
      return xmlResponse({ mode: '0' });
    }
    if (cmd === 'ptzMoveLeft' || cmd === 'ptzStopRun' || cmd === 'mirrorVideo') {
      return xmlResponse({});
    }
    return xmlResponse({});
  }) as typeof fetch;

  try {
    const client = new FoscamClient({ host: '192.168.1.40', username: 'admin', password: 'secret', rtspPort: 554 });
    const snapshot = await client.getSnapshot();
    expect(snapshot.connected).toBeTrue();
    expect(snapshot.deviceInfo.name).toEqual('Porch Foscam');
    expect(snapshot.deviceInfo.model).toEqual('FI9821W');
    expect(snapshot.camera.rtspUrl).toEqual('rtsp://admin:secret@192.168.1.40:554/videoMain');
    expect(snapshot.switches.find((switchArg) => switchArg.key === 'is_mirror')?.isOn).toBeTrue();
    expect(snapshot.numbers.find((numberArg) => numberArg.key === 'speak_volume')?.value).toEqual(35);

    const image = await client.execute({ type: 'snapshot_image', service: 'snapshot' });
    expect((image as { contentType: string }).contentType).toEqual('image/jpeg');

    const ptz = await client.execute({ type: 'ptz', service: 'ptz', movement: 'left', travelTime: 0 });
    expect((ptz as { ok: boolean }).ok).toBeTrue();
    expect(requests.some((requestArg) => requestArg.includes('cmd=ptzMoveLeft'))).toBeTrue();
    expect(requests.some((requestArg) => requestArg.includes('cmd=ptzStopRun'))).toBeTrue();

    const mirror = await client.execute({ type: 'set_switch', service: 'turn_off', key: 'is_mirror', enabled: false });
    expect((mirror as { ok: boolean }).ok).toBeTrue();
    expect(requests.some((requestArg) => requestArg.includes('cmd=mirrorVideo') && requestArg.includes('isMirror=0'))).toBeTrue();
  } finally {
    globalThis.fetch = originalFetch;
  }
});

tap.test('does not pretend live commands succeeded without a live endpoint or successful result code', async () => {
  const clientWithoutHost = new FoscamClient({});
  let missingHostError = '';
  try {
    await clientWithoutHost.execute({ type: 'ptz', service: 'ptz', movement: 'left', travelTime: 0 });
  } catch (errorArg) {
    missingHostError = errorArg instanceof Error ? errorArg.message : String(errorArg);
  }
  expect(missingHostError.includes('commands require config.host')).toBeTrue();

  const originalFetch = globalThis.fetch;
  globalThis.fetch = (async (inputArg: RequestInfo | URL) => {
    const url = typeof inputArg === 'string' ? inputArg : inputArg instanceof URL ? inputArg.toString() : inputArg.url;
    const parsed = new URL(url);
    if (parsed.searchParams.get('cmd') === 'mirrorVideo') {
      return xmlResponse({}, -3);
    }
    return xmlResponse({});
  }) as typeof fetch;

  try {
    const client = new FoscamClient({ host: '192.168.1.40', username: 'admin', password: 'secret' });
    let commandError = '';
    try {
      await client.execute({ type: 'set_switch', service: 'turn_on', key: 'is_mirror', enabled: true });
    } catch (errorArg) {
      commandError = errorArg instanceof Error ? errorArg.message : String(errorArg);
    }
    expect(commandError.includes('not supported') || commandError.includes('access was denied')).toBeTrue();
  } finally {
    globalThis.fetch = originalFetch;
  }
});

tap.test('sets up Foscam runtime and preserves the Home Assistant alias class', async () => {
  const integration = new FoscamIntegration();
  const alias = new HomeAssistantFoscamIntegration();
  expect(alias instanceof FoscamIntegration).toBeTrue();
  expect(integration.domain).toEqual('foscam');

  const runtime = await integration.setup({
    connected: true,
    deviceInfo: { id: 'manual-foscam', name: 'Manual Foscam', manufacturer: 'Foscam', online: true },
    currentSettings: { motion_detection: true, device_volume: 15 },
  }, {});
  const devices = await runtime.devices();
  const entities = await runtime.entities();
  expect(devices[0].integrationDomain).toEqual('foscam');
  expect(entities.some((entityArg) => String(entityArg.platform) === 'camera')).toBeTrue();
  await runtime.destroy();
});

const xmlResponse = (valuesArg: Record<string, string | number>, resultArg = 0): Response => {
  const body = [
    '<CGI_Result>',
    `<result>${resultArg}</result>`,
    ...Object.entries(valuesArg).map(([key, value]) => `<${key}>${String(value)}</${key}>`),
    '</CGI_Result>',
  ].join('');
  return new Response(body, { headers: { 'content-type': 'text/xml' } });
};

export default tap.start();
