import { randomBytes, createHash } from "crypto";
import type { APIRoute } from "astro";
import { createAccessToken } from "../../../lib/db/accessTokens";
import { getUserByNickOrEmail } from "../../../lib/db/users";
import config from '../../../../config.json';
import AccessToken from "../../../types/AccessToken";
import locationManager from "../../../lib/classes/managers/LocationManager";

export const POST: APIRoute = async({ request }) => {
    const data = await request.json().catch(() => {return new Response(
        JSON.stringify({
            code: 400,
            message: "Bad Request",
            error: "Invalid JSON"
        }), { status: 400 }
    )});

    if(!data.username) return new Response(
        JSON.stringify({
            code: 400,
            message: "Bad Request",
            error: "Username is required"
        }), { status: 400 }
    )

    const header = request.headers.get("Authorization");
    const token = header?.split(" ")[1];

    if(!token) return new Response(
        JSON.stringify({
            code: 401,
            message: "Unauthorized",
            error: "Access Token is required"
        }), { status: 401 }
    )

    if(token !== config.MASTER_ACCESSTOKEN) return new Response(
        JSON.stringify({
            code: 401,
            message: "Unauthorized",
            error: "Invalid Access Token"
        }), { status: 401 }
    )
    else {
        const userFromDb = await getUserByNickOrEmail(data.username);
        if(!userFromDb) return new Response(
            JSON.stringify({
                code: 404,
                message: "Not found",
                error: `User ${data.username} not found`
            }), { status: 404 }
        )

        const now = new Date();
        const timestamp = Buffer.from(String(Date.now())).toString('base64url');
        const userEncoded = Buffer.from(userFromDb._id?.toString() ?? "").toString('base64url');
        const random = randomBytes(16).toString("base64url");
        const randomHashed = createHash("sha256").update(random).digest("hex");
        const expiresIn = (data.duration ?? 86400) * 1000;

        const tokenString = `A.${timestamp}.${userEncoded}.${random}`;

        const user = locationManager.getUser(userFromDb._id);
        if(!user) return new Response(
            JSON.stringify({
                code: 404,
                message: "Not found",
                error: `User ${data.username} not found`
            }), { status: 404 }
        )

        const accessToken: AccessToken = {
            type: "A",
            user,
            entropy: randomHashed.toString(),
            createdAt: now,
            expiresAt: new Date(now.getTime() + expiresIn),
            createdFrom: data.createdFrom ?? null
        };

        await createAccessToken(accessToken);

        return new Response(
            JSON.stringify({
                code: 200,
                message: "OK",
                accessToken: tokenString
            })
        );
    }
}