import http from "node:http";
const API_HOST = "eu.i.posthog.com"; // Change to "us.i.posthog.com" for the US region
const ASSET_HOST = "eu-assets.i.posthog.com"; // Change to "us-assets.i.posthog.com" for the US region
// Convert Node.js headers to Fetch API headers
const toHeaders = (headers: Record<string, string[] | undefined>): Headers =>
  Object.entries(headers).reduce((acc, [name, values]) => {
    values?.forEach((value) => acc.append(name, value));
    return acc;
  }, new Headers());
// Convert Fetch API headers to Node.js headers
const fromHeaders = (headers: Headers): Record<string, string[] | undefined> =>
  [...headers].reduce<Record<string, string[] | undefined>>(
    (acc, [name, value]) => {
      if (acc[name]) {
        acc[name] = [...acc[name], value];
      } else {
        acc[name] = [value];
      }
      return acc;
    },
    {},
  );
/**
 * Proxies an incoming HTTP request to the appropriate PostHog endpoint.
 */
export default function proxy({ prefix }: { prefix: string }) {
  return (
    request: http.IncomingMessage,
    response: http.ServerResponse,
    next: (err?: Error) => void,
  ): void => {
    if (!request.url?.startsWith(prefix)) {
      next();
      return;
    }
    const pathname = (request.url ?? "").slice(prefix.length);
    const posthogHost = pathname.startsWith("/static/") ? ASSET_HOST : API_HOST;
    // Rewrite headers
    const headers = toHeaders(request.headersDistinct);
    headers.set("host", posthogHost);
    if (request.headers.host) {
      headers.set("X-Forwarded-Host", request.headers.host);
    }
    if (request.socket.remoteAddress) {
      headers.set("X-Real-IP", request.socket.remoteAddress);
      headers.set("X-Forwarded-For", request.socket.remoteAddress);
    }
    // Remove sensitive or hop-by-hop headers
    headers.delete("cookie");
    headers.delete("connection"); // https://datatracker.ietf.org/doc/html/rfc7230#section-6.1
    fetch(new URL(pathname, `https://${posthogHost}`), {
      method: request.method ?? "",
      headers,
      ...(!["HEAD", "GET"].includes(request.method ?? "")
        ? {
            body: request,
            duplex: "half",
          }
        : {}),
    })
      .then(async (res: Response) => {
        const headers = new Headers(res.headers);
        const body = await res.text();
        // See https://github.com/nodejs/undici/issues/2514
        if (headers.has("content-encoding")) {
          headers.delete("content-encoding");
          headers.delete("content-length");
        }
        response.writeHead(res.status, fromHeaders(headers));
        response.end(body);
      })
      .catch((e: unknown) => {
        next(new Error("Bad gateway", { cause: e }));
      });
  };
}