import { createServer } from 'node:http';
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { PiHoleClient, PiHoleIntegration, type IPiHoleSnapshot } from '../../ts/integrations/pi_hole/index.js';

const snapshot: IPiHoleSnapshot = {
  online: true,
  apiVersion: 6,
  status: 'enabled',
  statistics: {
    adsBlocked: 1,
    adsPercentage: 10,
    clientsSeen: 1,
    dnsQueries: 10,
    domainsBlocked: 100,
    queriesCached: 2,
    queriesForwarded: 7,
    uniqueClients: 1,
    uniqueDomains: 8,
  },
  versions: { core: {}, web: {}, ftl: {} },
  name: 'Pi-hole',
};

tap.test('reads Pi-hole v6 local HTTP API and executes disable through HTTP', async () => {
  const requests: Array<{ method?: string; url?: string; sid?: string; csrf?: string; body?: string }> = [];
  const server = createServer((requestArg, responseArg) => {
    let body = '';
    requestArg.on('data', (chunkArg) => { body += String(chunkArg); });
    requestArg.on('end', () => {
      requests.push({
        method: requestArg.method,
        url: requestArg.url,
        sid: requestArg.headers['x-ftl-sid'] as string | undefined,
        csrf: requestArg.headers['x-ftl-csrf'] as string | undefined,
        body,
      });
      responseArg.setHeader('content-type', 'application/json');
      if (requestArg.method === 'POST' && requestArg.url === '/api/auth') {
        responseArg.end(JSON.stringify({ session: { valid: true, sid: 'sid-1', csrf: 'csrf-1', validity: 300 } }));
        return;
      }
      if (requestArg.method === 'GET' && requestArg.url === '/api/stats/summary') {
        responseArg.end(JSON.stringify({ queries: { blocked: 5, percent_blocked: 25, total: 20, cached: 4, forwarded: 10, unique_domains: 12 }, clients: { total: 3, active: 2 }, gravity: { domains_being_blocked: 100000 } }));
        return;
      }
      if (requestArg.method === 'GET' && requestArg.url === '/api/dns/blocking') {
        responseArg.end(JSON.stringify({ blocking: 'enabled' }));
        return;
      }
      if (requestArg.method === 'GET' && requestArg.url === '/api/info/version') {
        responseArg.end(JSON.stringify({ version: { core: { local: { version: 'v6.0', hash: 'a' }, remote: { version: 'v6.0', hash: 'a' } }, web: {}, ftl: {} } }));
        return;
      }
      if (requestArg.method === 'POST' && requestArg.url === '/api/dns/blocking') {
        responseArg.end(JSON.stringify({ blocking: false, timer: 15 }));
        return;
      }
      responseArg.statusCode = 404;
      responseArg.end(JSON.stringify({ error: 'not found' }));
    });
  });

  await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
  try {
    const address = server.address();
    const port = typeof address === 'object' && address ? address.port : 0;
    const runtime = await new PiHoleIntegration().setup({ host: '127.0.0.1', port, apiKey: 'secret', apiVersion: 6, timeoutMs: 1000 }, {});
    const entities = await runtime.entities();
    const result = await runtime.callService?.({
      domain: 'switch',
      service: 'turn_off',
      target: { entityId: entities.find((entityArg) => entityArg.platform === 'switch')?.id },
      data: { duration: '00:00:15' },
    });

    const disableRequest = requests.find((requestArg) => requestArg.method === 'POST' && requestArg.url === '/api/dns/blocking');
    expect(entities.find((entityArg) => entityArg.id === 'sensor.pi_hole_dns_queries')?.state).toEqual(20);
    expect(result?.success).toBeTrue();
    expect(disableRequest?.sid).toEqual('sid-1');
    expect(disableRequest?.csrf).toEqual('csrf-1');
    expect(JSON.parse(disableRequest?.body || '{}')).toEqual({ blocking: false, timer: 15 });
    await runtime.destroy();
  } finally {
    await new Promise<void>((resolve, reject) => server.close((errorArg) => errorArg ? reject(errorArg) : resolve()));
  }
});

tap.test('does not report snapshot-only Pi-hole commands as successful', async () => {
  const runtime = await new PiHoleIntegration().setup({ snapshot }, {});
  const switchEntity = (await runtime.entities()).find((entityArg) => entityArg.platform === 'switch');
  const result = await runtime.callService?.({
    domain: 'switch',
    service: 'turn_off',
    target: { entityId: switchEntity?.id },
  });

  expect(result?.success).toBeFalse();
  expect(result?.error).toEqual('Pi-hole live commands require config.host or commandExecutor; snapshot-only commands are not reported as successful.');
  await runtime.destroy();
});

tap.test('does not fake refresh success without HTTP endpoint or snapshot', async () => {
  const client = new PiHoleClient({});
  const snapshotResult = await client.getSnapshot();
  const refreshResult = await client.refresh();

  expect(snapshotResult.online).toBeFalse();
  expect(refreshResult.success).toBeFalse();
  expect(refreshResult.error).toContain('endpoint');
});

export default tap.start();
