import process from "node:process";

const EDGE_TEST_BROKER_URL = process.env.EDGE_TEST_BROKER_URL || "";
const EDGE_TEST_GATEWAY_ID = process.env.EDGE_TEST_GATEWAY_ID || "";
const EDGE_TEST_AGENT_TOKEN = process.env.EDGE_TEST_AGENT_TOKEN || "";
const EDGE_TEST_BEHAVIOR = process.env.EDGE_TEST_BEHAVIOR || "success";

function normalizeBrokerUrl(rawUrl) {
  if (!rawUrl) {
    throw new Error("Missing EDGE_TEST_BROKER_URL");
  }

  const url = new URL(rawUrl);
  if (["127.0.0.1", "localhost", "0.0.0.0"].includes(url.hostname)) {
    url.hostname = "host.docker.internal";
  }
  return url;
}

function buildAgentWsUrl() {
  if (!EDGE_TEST_GATEWAY_ID) {
    throw new Error("Missing EDGE_TEST_GATEWAY_ID");
  }
  if (!EDGE_TEST_AGENT_TOKEN) {
    throw new Error("Missing EDGE_TEST_AGENT_TOKEN");
  }

  const url = normalizeBrokerUrl(EDGE_TEST_BROKER_URL);
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
  url.pathname = "/ws/agent";
  url.search = new URLSearchParams({
    gatewayId: EDGE_TEST_GATEWAY_ID,
    token: EDGE_TEST_AGENT_TOKEN,
  }).toString();
  return url.toString();
}

function sendJson(socket, payload) {
  socket.send(JSON.stringify(payload));
}

if (EDGE_TEST_BEHAVIOR === "offline") {
  console.log("fake-agent-offline");
  process.exit(0);
}

const socket = new WebSocket(buildAgentWsUrl());
const keepAlive = setInterval(() => {}, 1_000);

socket.addEventListener("open", () => {
  console.log(`fake-agent-open:${EDGE_TEST_BEHAVIOR}`);
});

socket.addEventListener("message", ({ data }) => {
  const message = JSON.parse(String(data));

  if (message.type === "COMMAND") {
    if (EDGE_TEST_BEHAVIOR === "timeout") {
      return;
    }

    sendJson(socket, {
      type: "COMMAND_RESULT",
      commandId: message.commandId,
      ok: true,
      payload: {
        source: "fake-agent",
        commandType: message.commandType,
        echo: message.payload || {},
      },
    });
    return;
  }

  if (message.type === "OPEN_ROOT_SHELL") {
    if (EDGE_TEST_BEHAVIOR === "shell-open-fail") {
      socket.close();
      return;
    }

    sendJson(socket, {
      type: "SHELL_OPENED",
      sessionId: message.payload.sessionId,
    });
    sendJson(socket, {
      type: "SHELL_OUTPUT",
      sessionId: message.payload.sessionId,
      data: "root@fake-agent:~# ",
    });
    return;
  }

  if (message.type === "SHELL_INPUT") {
    sendJson(socket, {
      type: "SHELL_OUTPUT",
      sessionId: message.payload.sessionId,
      data: `echo:${String(message.payload.data || "")}`,
    });
    return;
  }

  if (message.type === "CLOSE_ROOT_SHELL") {
    sendJson(socket, {
      type: "SHELL_EXIT",
      sessionId: message.payload.sessionId,
      code: 0,
    });
    socket.close();
  }
});

socket.addEventListener("error", (event) => {
  console.error("fake-agent-error", event?.message || "");
  process.exitCode = 1;
});

socket.addEventListener("close", () => {
  clearInterval(keepAlive);
  setTimeout(() => process.exit(process.exitCode || 0), 25);
});
