import { decodeToken } from "#lib/auth/token.js";
import { hashPassword } from "#lib/password.js";
import { prisma } from "#lib/server/prisma.js";
import { APIError, TypesafeAPIContextWithRequest } from "astro-typesafe-api/server";
import { z } from "zod";

export async function checkAuthorizationHeaderNoThrow(authorization: string): Promise<ReturnType<typeof checkAuthorizationHeader> | null> {
	try {
		return await checkAuthorizationHeader(authorization)
	} catch(e) {
		return null
	}
}

export async function checkAuthorizationHeader(authorization: string) {
	if (!authorization) {
		throw new APIError({
			code: "BAD_REQUEST",
			message: "Request is missing an 'Authorization' header."
		})
	}

	if (authorization.startsWith("Basic")) {
		const payload = btoa(authorization.split(" ")[1]).split(":");

		if (payload.length !== 2) {
			throw new APIError({
				code: "BAD_REQUEST",
				message: "Malformed 'Authorization' header."
			})
		}

		const [email, password] = payload;

		const user = await prisma.benutzer.findUnique({
			where: {
				email
			}
		})

		if (!user || user.passwort !== hashPassword(password)) {
			throw new APIError({
				code: "UNAUTHORIZED",
				message: "Unknown combination of email and password."
			})
		}

		return user;
	} else if (authorization.startsWith("Bearer")) {
		const token = authorization.split(" ")[1]

		if (!token) {
			throw new APIError({
				code: "BAD_REQUEST",
				message: "Malformed 'Authorization' header."
			})
		}

		const payload = decodeToken(token)

		if ((payload.exp || 0) < Date.now()) {
			throw new APIError({
				code: "UNAUTHORIZED",
				message: "Access Token has expired."
			})
		}

		const user = await prisma.benutzer.findUnique({
			where: {
				uid: payload.uid
			}
		})

		if (!user) {
			throw new APIError({
				code: "UNAUTHORIZED",
				message: "Invalid Bearer Token."
			})
		}

		return user;
	}

	throw new APIError({
		code: "BAD_REQUEST",
		message: "Invalid authorization method in 'Authorization' header."
	})
}

export async function authorizationMiddleware(input: any, ctx: TypesafeAPIContextWithRequest<any>) {
	return await checkAuthorizationHeader(ctx.request.headers.get("Authorization"));
}

export async function maybeAuthorizationMiddleware(input: any, ctx: TypesafeAPIContextWithRequest<any>) {
	try {
		return authorizationMiddleware(input, ctx)
	} catch(e) {
		return null;
	}
}

export const authorizationHeaders = {
	Authorization: z.string()
}

export async function adminMiddleware(input: any, ctx: TypesafeAPIContextWithRequest<any>) {	
	try {
		const user = await authorizationMiddleware(input, ctx)

		if (user.rolle === "ADMIN") {
			return user
		}
	} catch(e) {
	}

	throw new APIError({
		code: "FORBIDDEN",
		"message": "Diese Route ist für Admins vorbehalten."
	})
}