import type { IncomingMessage, ServerResponse } from "node:http";

const DEFAULT_BODY_LIMIT_BYTES = 64 * 1024;

export async function handleCaseRunHttp(request: IncomingMessage, response: ServerResponse, url: URL, options: any = {}) {
  const env = options.env ?? process.env;
  const baseUrl = String(env.HARNESSRL_API_URL ?? "").trim().replace(/\/+$/u, "");
  if (!baseUrl) return sendJson(response, 503, { ok: false, error: { code: "harnessrl_api_url_required", message: "HARNESSRL_API_URL is required for CaseRun routes" } });
  try {
    const target = new URL(`${url.pathname}${url.search}`, `${baseUrl}/`);
    const headers = new Headers();
    for (const [name, value] of Object.entries(request.headers)) {
      if (value === undefined || name.toLowerCase() === "host" || name.toLowerCase() === "content-length") continue;
      headers.set(name, Array.isArray(value) ? value.join(",") : value);
    }
    headers.set("x-forwarded-host", String(request.headers["x-forwarded-host"] ?? request.headers.host ?? ""));
    headers.set("x-forwarded-proto", String(request.headers["x-forwarded-proto"] ?? "http"));
    const body = request.method === "GET" || request.method === "HEAD" ? undefined : await readBody(request, DEFAULT_BODY_LIMIT_BYTES);
    const upstream = await (options.fetchImpl ?? globalThis.fetch)(target, { method: request.method, headers, body });
    response.statusCode = upstream.status;
    for (const [name, value] of upstream.headers) if (name.toLowerCase() !== "content-length" && name.toLowerCase() !== "transfer-encoding") response.setHeader(name, value);
    response.end(Buffer.from(await upstream.arrayBuffer()));
  } catch (error: any) {
    sendJson(response, 502, { ok: false, error: { code: error?.code ?? "harnessrl_api_unavailable", message: error?.message ?? String(error) } });
  }
}

export function caseRunInternalFetch(fetchImpl: typeof fetch, internalApiUrl: string, env: Record<string, string | undefined>) {
  const apiKey = String(env.HWLAB_BOOTSTRAP_ADMIN_API_KEY ?? "").trim();
  if (!apiKey) return fetchImpl;
  const internalOrigin = new URL(internalApiUrl).origin;
  return async (input: URL | RequestInfo, init: RequestInit = {}) => {
    const target = new URL(typeof input === "string" || input instanceof URL ? input : input.url);
    if (target.origin !== internalOrigin) return fetchImpl(input, init);
    const headers = new Headers(input instanceof Request ? input.headers : undefined);
    new Headers(init.headers).forEach((value, name) => headers.set(name, value));
    if (!headers.has("authorization")) headers.set("authorization", `Bearer ${apiKey}`);
    return fetchImpl(input, { ...init, headers });
  };
}

async function readBody(request: IncomingMessage, limitBytes: number) {
  let size = 0;
  const chunks: Buffer[] = [];
  for await (const chunk of request) {
    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
    size += buffer.length;
    if (size > limitBytes) throw Object.assign(new Error(`body exceeds ${limitBytes} bytes`), { code: "body_too_large" });
    chunks.push(buffer);
  }
  return Buffer.concat(chunks);
}

function sendJson(response: ServerResponse, status: number, body: unknown) {
  response.statusCode = status;
  response.setHeader("content-type", "application/json; charset=utf-8");
  response.setHeader("cache-control", "no-store");
  response.end(`${JSON.stringify(body)}\n`);
}
