import { ObjectId } from "mongodb";
import AccessToken from "../../types/AccessToken";
import { getAccessToken } from "../db/accessTokens";
import { getUserById } from "../db/users";
import locationManager from "../classes/managers/LocationManager";

export default async function validateAccessToken(request: Request): Promise<Response | AccessToken> {
    let accessToken;
    const authorization = request.headers.get("Authorization");
    if(authorization !== null && authorization.startsWith("Bearer ")) accessToken = authorization.split(" ")[1];

    const cookies = request.headers.get("Cookie")?.split(";").map((x) => x.trim().split("=")) ?? [];

    if(accessToken === undefined) accessToken = cookies.filter((x) => x[0] === "sessionToken")[0]?.[1];

    if(accessToken === undefined) return new Response(
        JSON.stringify({
            code: 401,
            message: "Unauthorized",
            error: "Missing Access Token"
        }), { status: 401 }
    );

    const response = await getAccessToken(accessToken);

    if(response === null) return new Response(
        JSON.stringify({
            code: 401,
            message: "Unauthorized",
            error: "Invalid Access Token"
        }), { status: 401 }
    );

    const user = await getUserById(response.user as ObjectId);
    if(!user) return new Response (
        JSON.stringify({
            code: 404,
            message: "Not found",
            data: "Access token does not match any user"
        }), { status: 404 }
    );
    
    if(response.createdAt.getTime() > Date.now()) return new Response(
        JSON.stringify({
            code: 403,
            message: "Forbidden",
            data: "Access token is invalid for user " + user.username + ", are you travelling in time?"
        }), { status: 403 }
    );
    
    if(response.expiresAt !== null && response.expiresAt.getTime() < Date.now()) return new Response(
        JSON.stringify({
            code: 403,
            message: "Forbidden",
            data: "Access token is invalid for user " + user.username + ", token expired"
        }), { status: 403 }
    );

    return {
        type: response.type,
        user: locationManager.getUser(user._id),
        entropy: response.entropy,
        createdAt: response.createdAt,
        expiresAt: response.expiresAt,
        createdFrom: response.createdFrom
    } as AccessToken;
}