import { parse as parseCookie, serialize } from "cookie";
import { UnknownAction } from "../errors.js";
async function getBody(req) {
    if (!("body" in req) || !req.body || req.method !== "POST")
        return;
    const contentType = req.headers.get("content-type");
    if (contentType?.includes("application/json")) {
        return await req.json();
    }
    else if (contentType?.includes("application/x-www-form-urlencoded")) {
        const params = new URLSearchParams(await req.text());
        return Object.fromEntries(params);
    }
}
const actions = [
    "providers",
    "session",
    "csrf",
    "signin",
    "signout",
    "callback",
    "verify-request",
    "error",
];
export async function toInternalRequest(req) {
    try {
        // TODO: url.toString() should not include action and providerId
        // see init.ts
        const url = new URL(req.url.replace(/\/$/, ""));
        // FIXME: Upstream issue in Next.js, pathname segments get included as part of the query string
        url.searchParams.delete("nextauth");
        const { pathname } = url;
        const action = actions.find((a) => pathname.includes(a));
        if (!action) {
            throw new UnknownAction(`Cannot detect action in pathname (${pathname}).`);
        }
        if (req.method !== "GET" && req.method !== "POST") {
            throw new UnknownAction("Only GET and POST requests are supported.");
        }
        const providerIdOrAction = pathname.split("/").pop();
        let providerId;
        if (providerIdOrAction &&
            !action.includes(providerIdOrAction) &&
            ["signin", "callback"].includes(action)) {
            providerId = providerIdOrAction;
        }
        return {
            url,
            action,
            providerId,
            method: req.method,
            headers: Object.fromEntries(req.headers),
            body: req.body ? await getBody(req) : undefined,
            cookies: parseCookie(req.headers.get("cookie") ?? "") ?? {},
            error: url.searchParams.get("error") ?? undefined,
            query: Object.fromEntries(url.searchParams),
        };
    }
    catch (e) {
        return e;
    }
}
export function toResponse(res) {
    const headers = new Headers(res.headers);
    res.cookies?.forEach((cookie) => {
        const { name, value, options } = cookie;
        const cookieHeader = serialize(name, value, options);
        if (headers.has("Set-Cookie"))
            headers.append("Set-Cookie", cookieHeader);
        else
            headers.set("Set-Cookie", cookieHeader);
    });
    let body = res.body;
    if (headers.get("content-type") === "application/json")
        body = JSON.stringify(res.body);
    else if (headers.get("content-type") === "application/x-www-form-urlencoded")
        body = new URLSearchParams(res.body).toString();
    const status = res.redirect ? 302 : res.status ?? 200;
    const response = new Response(body, { headers, status });
    if (res.redirect)
        response.headers.set("Location", res.redirect);
    return response;
}
/** Web compatible method to create a hash, using SHA256 */
export async function createHash(message) {
    const data = new TextEncoder().encode(message);
    const hash = await crypto.subtle.digest("SHA-256", data);
    return Array.from(new Uint8Array(hash))
        .map((b) => b.toString(16).padStart(2, "0"))
        .join("")
        .toString();
}
/** Web compatible method to create a random string of a given length */
export function randomString(size) {
    const i2hex = (i) => ("0" + i.toString(16)).slice(-2);
    const r = (a, i) => a + i2hex(i);
    const bytes = crypto.getRandomValues(new Uint8Array(size));
    return Array.from(bytes).reduce(r, "");
}
