import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { HomeWizardClient, HomeWizardConfigFlow, HomeWizardIntegration, HomeWizardMapper, type IHomeWizardRawData } from '../../ts/integrations/homewizard/index.js';

const readBody = async (requestArg: 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 json = (responseArg: ServerResponse, valueArg: unknown, statusArg = 200): void => {
  responseArg.statusCode = statusArg;
  responseArg.setHeader('content-type', 'application/json');
  responseArg.end(JSON.stringify(valueArg));
};

tap.test('reads HomeWizard v1 snapshots over local HTTP and writes real commands', async () => {
  const requests: Array<{ method?: string; url?: string; body?: string }> = [];
  const server = createServer((requestArg: IncomingMessage, responseArg: ServerResponse) => {
    void (async () => {
      const body = requestArg.method === 'PUT' || requestArg.method === 'POST' ? await readBody(requestArg) : undefined;
      requests.push({ method: requestArg.method, url: requestArg.url, body });
      const url = new URL(requestArg.url || '/', 'http://127.0.0.1');

      if (url.pathname === '/api') {
        json(responseArg, { product_type: 'HWE-SKT', product_name: 'Energy Socket', serial: 'AABBCCDDEEFF', firmware_version: '4.12', api_version: 'v1' });
        return;
      }
      if (url.pathname === '/api/v1/data') {
        json(responseArg, { total_power_import_kwh: 30.511, active_power_w: 42, active_voltage_v: 230, wifi_ssid: 'Local', wifi_strength: 91 });
        return;
      }
      if (url.pathname === '/api/v1/system') {
        if (requestArg.method === 'PUT') {
          expect(body).toContain('cloud_enabled');
          json(responseArg, JSON.parse(body || '{}'));
          return;
        }
        json(responseArg, { cloud_enabled: true });
        return;
      }
      if (url.pathname === '/api/v1/state') {
        if (requestArg.method === 'PUT') {
          json(responseArg, JSON.parse(body || '{}'));
          return;
        }
        json(responseArg, { power_on: true, switch_lock: false, brightness: 255 });
        return;
      }
      if (url.pathname === '/api/v1/identify') {
        json(responseArg, { identify: 'ok' });
        return;
      }
      responseArg.statusCode = 404;
      responseArg.end('{}');
    })().catch((errorArg) => {
      responseArg.statusCode = 500;
      responseArg.end(String(errorArg));
    });
  });

  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 url = `http://127.0.0.1:${port}`;
    const client = new HomeWizardClient({ url, apiVersion: 'v1', timeoutMs: 1000 });
    const snapshot = await client.getSnapshot(true);
    const runtime = await new HomeWizardIntegration().setup({ url, apiVersion: 'v1', timeoutMs: 1000 }, {});
    const entities = await runtime.entities();
    const powerSwitch = entities.find((entityArg) => entityArg.attributes?.key === 'power_on')!;
    const brightness = entities.find((entityArg) => entityArg.attributes?.key === 'status_light_brightness')!;
    const cloudSwitch = entities.find((entityArg) => entityArg.attributes?.key === 'cloud_connection')!;

    const powerResult = await runtime.callService?.({ domain: 'switch', service: 'turn_off', target: { entityId: powerSwitch.id } });
    const brightnessResult = await runtime.callService?.({ domain: 'number', service: 'set_value', target: { entityId: brightness.id }, data: { value: 50 } });
    const cloudResult = await runtime.callService?.({ domain: 'switch', service: 'turn_off', target: { entityId: cloudSwitch.id } });
    const identifyResult = await runtime.callService?.({ domain: 'homewizard', service: 'identify', target: {} });

    expect(snapshot.online).toBeTrue();
    expect(snapshot.source).toEqual('http');
    expect(snapshot.measurement.energy_import_kwh).toEqual(30.511);
    expect(powerResult?.success).toBeTrue();
    expect(brightnessResult?.success).toBeTrue();
    expect(cloudResult?.success).toBeTrue();
    expect(identifyResult?.success).toBeTrue();
    expect(requests.some((requestArg) => requestArg.url === '/api/v1/state' && requestArg.method === 'PUT' && requestArg.body?.includes('power_on'))).toBeTrue();
    expect(requests.some((requestArg) => requestArg.url === '/api/v1/state' && requestArg.method === 'PUT' && requestArg.body?.includes('brightness'))).toBeTrue();
    expect(requests.some((requestArg) => requestArg.url === '/api/v1/system' && requestArg.method === 'PUT')).toBeTrue();
    await runtime.destroy();
  } finally {
    await new Promise<void>((resolve, reject) => server.close((errorArg) => errorArg ? reject(errorArg) : resolve()));
  }
});

tap.test('does not report live command success for static HomeWizard snapshots', async () => {
  const rawData: Partial<IHomeWizardRawData> = {
    device: { product_type: 'HWE-SKT', product_name: 'Static Socket', serial: 'STATIC123456', api_version: 'v1' },
    measurement: { active_power_w: 1, total_power_import_kwh: 2 },
    state: { power_on: true, switch_lock: false, brightness: 255 },
    system: { cloud_enabled: true },
  };
  const snapshot = HomeWizardMapper.toSnapshot({ config: { name: 'Static Socket' }, rawData, online: true, source: 'manual' });
  const runtime = await new HomeWizardIntegration().setup({ snapshot }, {});
  const entity = (await runtime.entities()).find((entityArg) => entityArg.attributes?.key === 'power_on')!;
  const result = await runtime.callService?.({ domain: 'switch', service: 'turn_off', target: { entityId: entity.id } });

  expect(result?.success).toBeFalse();
  expect(result?.error).toContain('Static snapshots/manual data are read-only');
  await runtime.destroy();
});

tap.test('requests HomeWizard API v2 tokens during config flow and validates the local snapshot', async () => {
  const server = createServer((requestArg: IncomingMessage, responseArg: ServerResponse) => {
    void (async () => {
      const url = new URL(requestArg.url || '/', 'http://127.0.0.1');
      if (url.pathname === '/api/user' && requestArg.method === 'POST') {
        await readBody(requestArg);
        json(responseArg, { name: 'local/smarthome-exchange', token: 'ABCDEF0123456789ABCDEF0123456789' });
        return;
      }
      if (url.pathname === '/api') {
        expect(requestArg.headers.authorization).toEqual('Bearer ABCDEF0123456789ABCDEF0123456789');
        json(responseArg, { product_type: 'HWE-P1', product_name: 'P1 Meter', serial: '112233445566', firmware_version: '6.04', api_version: '2.2.0' });
        return;
      }
      if (url.pathname === '/api/measurement') {
        json(responseArg, { energy_import_kwh: 12.3, power_w: -100 });
        return;
      }
      if (url.pathname === '/api/system') {
        json(responseArg, { wifi_ssid: 'Local', wifi_rssi_db: -60, cloud_enabled: true, status_led_brightness_pct: 80, api_v1_enabled: true });
        return;
      }
      responseArg.statusCode = 404;
      responseArg.end('{}');
    })().catch((errorArg) => {
      responseArg.statusCode = 500;
      responseArg.end(String(errorArg));
    });
  });

  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 flow = new HomeWizardConfigFlow();
    const step = await flow.start({ source: 'manual', host: '127.0.0.1', port, name: 'P1 Meter', metadata: { apiVersion: 'v2', protocol: 'http' } }, {});
    const done = await step.submit!({ tokenName: 'smarthome-exchange' });

    expect(done.kind).toEqual('done');
    expect(done.config?.apiVersion).toEqual('v2');
    expect(done.config?.token).toEqual('ABCDEF0123456789ABCDEF0123456789');
    expect(done.config?.uniqueId).toEqual('HWE-P1_112233445566');
  } finally {
    await new Promise<void>((resolve, reject) => server.close((errorArg) => errorArg ? reject(errorArg) : resolve()));
  }
});

export default tap.start();
