interface FlueFetchOptions {
  readonly baseUrl: URL;
  readonly fetchImpl?: typeof fetch;
  readonly generateRequestId?: () => string;
}

/**
 * Build the Flue transport used by the browser client.
 *
 * The installed Flue SDK does not expose per-call headers on `agents.send`.
 * Its custom `fetch` seam does receive the resolved URL and method, so request
 * IDs are attached here to each agent admission POST. History and Durable
 * Streams observation requests are GETs and intentionally remain untagged.
 */
export const createFlueFetch = ({
  baseUrl,
  fetchImpl = fetch,
  generateRequestId = crypto.randomUUID,
}: FlueFetchOptions): typeof fetch => {
  const basePath = baseUrl.pathname.replace(/\/+$/u, "");

  return async (input, init) => {
    const inputUrl =
      typeof input === "string" || input instanceof URL ? input : input.url;
    const requestUrl = new URL(inputUrl, baseUrl);
    const method = (
      init?.method ?? (input instanceof Request ? input.method : "GET")
    ).toUpperCase();
    const relativePath = requestUrl.pathname.startsWith(`${basePath}/`)
      ? requestUrl.pathname.slice(basePath.length)
      : requestUrl.pathname;
    const pathSegments = relativePath.split("/").filter(Boolean);
    const isAgentAdmission =
      method === "POST" &&
      pathSegments.length === 3 &&
      pathSegments[0] === "agents";

    let requestInit = init;
    if (isAgentAdmission) {
      const headers = new Headers(
        input instanceof Request ? input.headers : undefined
      );
      for (const [key, value] of new Headers(init?.headers).entries()) {
        headers.set(key, value);
      }
      headers.set("x-zopu-request-id", generateRequestId());
      requestInit = { ...init, headers };
    }

    const response = await fetchImpl(input, requestInit);
    if (
      !response.ok ||
      !response.headers.get("content-type")?.includes("application/json")
    ) {
      return response;
    }

    const body = (await response.clone().json()) as unknown;
    if (
      typeof body !== "object" ||
      body === null ||
      !("streamUrl" in body) ||
      typeof body.streamUrl !== "string"
    ) {
      return response;
    }

    const streamUrl = new URL(body.streamUrl);
    streamUrl.protocol = baseUrl.protocol;
    streamUrl.host = baseUrl.host;
    const headers = new Headers(response.headers);
    headers.set("location", streamUrl.toString());
    return Response.json(
      { ...body, streamUrl: streamUrl.toString() },
      {
        headers,
        status: response.status,
        statusText: response.statusText,
      }
    );
  };
};
