const assert = require("assert");
const http = require("http");
const express = require("express");
const {
  createWebhookService,
  generateSlug,
  sanitizeIdentifier,
  isTimestampWithinWindow
} = require("../src/services/webhooks");

async function main() {
  assert.strictEqual(sanitizeIdentifier("  Cozy Alerts!  "), "cozy-alerts");
  assert.strictEqual(
    generateSlug({
      identifier: "Cozy Alerts",
      uuid: "123e4567-e89b-42d3-a456-426614174000"
    }),
    "cozy-alerts-123e4567-e89b-42d3-a456-426614174000"
  );
  assert.throws(() => sanitizeIdentifier("../"));
  assert.strictEqual(
    isTimestampWithinWindow(String(Math.floor(Date.now() / 1000))),
    true
  );

  const service = createWebhookService();
  const app = express();
  app.use("/webhooks", service.router);
  let observed = null;
  service.registerInbound({
    pluginId: "verification",
    endpointId: "raw-body",
    namespace: "test",
    slug: "raw-body",
    handler: async (context) => {
      observed = context;
      return { status: 202, body: { accepted: true } };
    }
  });
  const server = http.createServer(app);
  await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
  const raw = '{"z":1, "a":2}';
  const response = await fetch(
    `http://127.0.0.1:${server.address().port}/webhooks/test/raw-body`,
    {
      method: "POST",
      headers: { "Content-Type": "application/json; charset=utf-8" },
      body: raw
    }
  );
  assert.strictEqual(response.status, 202);
  assert.strictEqual(observed.rawBodyText, raw);
  assert.deepStrictEqual(observed.parsedJson, { z: 1, a: 2 });
  const methodResponse = await fetch(
    `http://127.0.0.1:${server.address().port}/webhooks/test/raw-body`
  );
  assert.strictEqual(methodResponse.status, 405);
  const unknownResponse = await fetch(
    `http://127.0.0.1:${server.address().port}/webhooks/test/unknown`,
    { method: "POST", body: "{}" }
  );
  assert.strictEqual(unknownResponse.status, 404);

  const receiver = http.createServer((req, res) => {
    let body = "";
    req.setEncoding("utf8");
    req.on("data", (chunk) => {
      body += chunk;
    });
    req.on("end", () => {
      res.writeHead(201, { "Content-Type": "text/plain" });
      res.end(body);
    });
  });
  await new Promise((resolve) => receiver.listen(0, "127.0.0.1", resolve));
  const outbound = await service.sendJson({
    pluginId: "verification",
    url: `http://127.0.0.1:${receiver.address().port}/receive`,
    payload: { hello: "world" }
  });
  assert.strictEqual(outbound.status, 201);
  assert.strictEqual(outbound.success, true);
  assert.strictEqual(outbound.body, '{"hello":"world"}');

  await new Promise((resolve) => server.close(resolve));
  await new Promise((resolve) => receiver.close(resolve));
  console.log("Webhook framework verification passed.");
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
