import { z } from "zod";
import moment from "moment";
import { prisma } from "#lib/server/prisma.js";
import { encodeToken } from "../../../lib/auth/token.js";
import { validatePassword } from "../../../lib/password.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { TokenType } from "#lib/auth/types.js";
import { UUidWithPrefix } from "#components/Ausweis/types.js";

export const GET = defineApiRoute({
	meta: {
		description:
			"Erstellt sowohl einen neuen Refresh Token als auch einen Access Token für den gegebenen Benutzer. Der Refresh Token kann später für die Erstellung neuer Access Token genutzt werden.",
		tags: ["Benutzer"],
		summary: "Refresh Token anfragen.",
	},
	input: z.object({
		email: z.string().email(),
		passwort: z.string().min(8).max(100),
	}),
	output: z.object({
		uid: UUidWithPrefix,
		accessToken: z.string(),
		refreshToken: z.string(),
		refreshTokenBase64: z.string(),
		accessTokenBase64: z.string(),
		exp: z.number(),
	}),
	async fetch(input, ctx) {
		// Falls der Nutzer nicht existiert, wird eine Fehlermeldung zurückgegeben.
		const user = await prisma.benutzer.findUnique({
			where: {
				email: input.email,
			},
		});

		if (!user) {
			throw new APIError({
				code: "BAD_REQUEST",
				message: "Benutzer konnte nicht gefunden werden.",
			});
		}

		// Falls das Passwort nicht stimmt, wird eine Fehlermeldung zurückgegeben.
		if (!validatePassword(user.passwort, input.passwort)) {
			throw new APIError({
				code: "BAD_REQUEST",
				message: "Benutzer konnte nicht gefunden werden.",
			});
		}

		const refreshTokenExpiry = moment().add(30, "days");
		const accessToken = encodeToken({
			uid: user.uid,
			typ: TokenType.Access,
			exp: moment().add(30, "minutes").valueOf(),
		});
		const refreshToken = encodeToken({
			uid: user.uid,
			typ: TokenType.Refresh,
			exp: refreshTokenExpiry.valueOf(),
		});

		const { id } = await prisma.refreshTokens.create({
			data: {
				token: refreshToken,
				benutzer_id: user.id,
				ip: "",
				expiry: refreshTokenExpiry.toDate(),
			},
		});

		return {
			uid: user.uid,
			accessToken,
			refreshToken,
			refreshTokenBase64: Buffer.from(refreshToken).toString("base64"),
			accessTokenBase64: Buffer.from(accessToken).toString("base64"),
			exp: refreshTokenExpiry.valueOf(),
		};
	},
});
