import { CookieOptions } from "@moduletrace/datasquirel/dist/package-shared/types";
import dayjs, { type Dayjs } from "dayjs";
import * as http from "http";
import { NextApiResponse } from "next";

type FinalCookieOpts = Omit<CookieOptions, "expires"> & { expires?: Dayjs };
type Cookie = { name: string; value: string; options: FinalCookieOpts };

export function setCookie(
    res: http.ServerResponse | NextApiResponse,
    cookies: Cookie[],
): void {
    const AllCookieParts: string[][] = [];

    for (let i = 0; i < cookies.length; i++) {
        const cookie = cookies[i];
        const { name, options, value } = cookie;

        const cookieParts: string[] = [
            `${encodeURIComponent(name)}=${encodeURIComponent(value)}`,
        ];

        if (options.expires) {
            cookieParts.push(
                `Expires=${options.expires.toDate().toUTCString()}`,
            );
        }
        if (options.maxAge !== undefined) {
            cookieParts.push(`Max-Age=${options.maxAge}`);
        }
        if (options.path) {
            cookieParts.push(`Path=${options.path}`);
        }
        if (options.domain) {
            cookieParts.push(`Domain=${options.domain}`);
        }
        if (options.secure) {
            cookieParts.push("Secure");
        }
        if (options.httpOnly) {
            cookieParts.push("HttpOnly");
        }

        AllCookieParts.push(cookieParts);
    }

    const final_cookie_string = AllCookieParts.map((ck) => ck.join("; "));

    res.setHeader("Set-Cookie", final_cookie_string);
}

export function getCookie(cookie_string: string, name: string): string | null {
    const cookies = cookie_string
        .split(";")
        .reduce((acc: { [key: string]: string }, cookie: string) => {
            const [key, val] = cookie.trim().split("=").map(decodeURIComponent);
            acc[key] = val;
            return acc;
        }, {});

    return cookies[name] || null;
}

export function updateCookie(
    res: http.ServerResponse,
    cookies: Cookie[],
): void {
    setCookie(res, cookies);
}

export function deleteCookie(
    res: http.ServerResponse,
    cookies: Pick<Cookie, "name" | "options">[],
): void {
    setCookie(
        res,
        cookies.map((ck) => ({
            ...ck,
            value: "",
            options: {
                ...ck.options,
                expires: dayjs().subtract(1, "day"),
                maxAge: 0,
            },
        })),
    );
}
