import * as http from 'node:http';
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { AirosClient, AirosIntegration, type IAirosCommand, type IAirosRawStatus } from '../../ts/integrations/airos/index.js';

const rawStatus: IAirosRawStatus = {
  host: {
    hostname: 'Roof Bridge',
    uptime: 12345,
    fwversion: 'v8.7.19',
    devmodel: 'LiteBeam 5AC',
    netrole: 'bridge',
    cpuload: 4.2,
  },
  services: { dhcpc: true, dhcpd: false, dhcp6d_stateful: false, pppoe: false },
  portfw: false,
  wireless: {
    mode: 'ap-ptp',
    essid: 'Backhaul',
    frequency: 5805,
    distance: 1200,
    antenna_gain: 23,
    polling: { dl_capacity: 210000, ul_capacity: 190000 },
    throughput: { tx: 12000, rx: 9000 },
  },
  interfaces: [{ ifname: 'br0', hwaddr: 'AA:BB:CC:DD:EE:FF', enabled: true }],
};

tap.test('does not fake airOS command success without host/client/executor', async () => {
  const runtime = await new AirosIntegration().setup({ name: 'Snapshot Bridge', rawStatus, nativeHttpEnabled: false }, {});
  const result = await runtime.callService?.({ domain: 'airos', service: 'reboot', target: {}, data: {} });

  expect(result?.success).toBeFalse();
  expect(result?.error || '').toContain('require host/password');
  await runtime.destroy();
});

tap.test('delegates airOS commands to an injected executor', async () => {
  let command: IAirosCommand | undefined;
  const runtime = await new AirosIntegration().setup({
    name: 'Executor Bridge',
    rawStatus,
    nativeHttpEnabled: false,
    commandExecutor: async (commandArg) => {
      command = commandArg;
      return { success: true, transmitted: true, data: { accepted: true } };
    },
  }, {});

  const result = await runtime.callService?.({ domain: 'airos', service: 'reboot', target: {}, data: {} });
  expect(result?.success).toBeTrue();
  expect(command?.action).toEqual('reboot');

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

tap.test('reads and commands a local airOS web API over native HTTP', async () => {
  const requests: Array<{ method?: string; url?: string; body: string }> = [];
  const server = http.createServer(async (request, response) => {
    const body = await readRequestBody(request);
    requests.push({ method: request.method, url: request.url, body });
    response.setHeader('Content-Type', 'application/json');

    if (request.url === '/api/auth' && request.method === 'POST') {
      response.setHeader('Set-Cookie', 'AIROS_SESSION=test; Path=/');
      response.setHeader('X-CSRF-ID', 'csrf-test');
      response.end('{}');
      return;
    }
    if (request.url === '/status.cgi') {
      expect(request.headers.cookie).toContain('AIROS_SESSION=test');
      response.end(JSON.stringify(rawStatus));
      return;
    }
    if (request.url === '/api/fw/update-check') {
      response.end(JSON.stringify({ update: true, version: 'v8.7.20', changelog: 'https://example.invalid/changelog.txt' }));
      return;
    }
    if (request.url === '/reboot.cgi') {
      expect(body).toContain('reboot=yes');
      response.end(JSON.stringify({ ok: true }));
      return;
    }
    if (request.url === '/api/fw/download') {
      response.end(JSON.stringify({ ok: true }));
      return;
    }
    if (request.url === '/fwflash.cgi') {
      expect(body).toContain('do_update');
      response.end(JSON.stringify({ ok: true, code: 0 }));
      return;
    }

    response.statusCode = 404;
    response.end(JSON.stringify({ error: 'not found' }));
  });

  await listen(server);
  const address = server.address();
  const port = typeof address === 'object' && address ? address.port : 0;
  try {
    const client = new AirosClient({ host: `127.0.0.1:${port}`, ssl: false, password: 'ubnt-password', timeoutMs: 1000 });
    const snapshot = await client.getSnapshot(true);
    const rebootResult = await client.sendCommand({ action: 'reboot', method: 'reboot.cgi', service: 'reboot', target: {}, host: snapshot.device.host });
    const runtime = await new AirosIntegration().setup({ host: `127.0.0.1:${port}`, ssl: false, password: 'ubnt-password', timeoutMs: 1000 }, {});
    const installResult = await runtime.callService?.({ domain: 'update', service: 'install', target: { entityId: 'update.roof_bridge_firmware_update' }, data: {} });

    expect(snapshot.connected).toBeTrue();
    expect(snapshot.source).toEqual('http');
    expect(snapshot.device.modelName).toEqual('LiteBeam 5AC');
    expect(snapshot.firmware?.version).toEqual('v8.7.20');
    expect(rebootResult.success).toBeTrue();
    expect(installResult?.success).toBeTrue();
    expect(requests.some((requestArg) => requestArg.url === '/status.cgi')).toBeTrue();
    expect(requests.some((requestArg) => requestArg.url === '/reboot.cgi')).toBeTrue();
    expect(requests.some((requestArg) => requestArg.url === '/api/fw/download')).toBeTrue();
    expect(requests.some((requestArg) => requestArg.url === '/fwflash.cgi')).toBeTrue();
    await runtime.destroy();
  } finally {
    await close(server);
  }
});

const readRequestBody = async (requestArg: http.IncomingMessage): Promise<string> => {
  const chunks: Buffer[] = [];
  for await (const chunk of requestArg) {
    chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
  }
  return Buffer.concat(chunks).toString('utf8');
};

const listen = async (serverArg: http.Server): Promise<void> => {
  await new Promise<void>((resolve, reject) => {
    serverArg.once('error', reject);
    serverArg.listen(0, '127.0.0.1', () => {
      serverArg.off('error', reject);
      resolve();
    });
  });
};

const close = async (serverArg: http.Server): Promise<void> => {
  await new Promise<void>((resolve, reject) => {
    serverArg.close((errorArg) => errorArg ? reject(errorArg) : resolve());
  });
};

export default tap.start();
