import { Users } from '../db/mongodb';
import { ObjectId } from 'mongodb';
import { hash } from 'argon2'
import DBUser from '../../types/db/DBUser';
import User from '../classes/User';
import AccessToken from '../../types/AccessToken';

export const getAllUsers = async () => {
    const users = await Users();
    return users.find({}).toArray() as Promise<DBUser[]>;
}

export const createUser = async (id: ObjectId, username: string, email: string, password: string, mainPlanet: ObjectId) => {
    const user: DBUser = {
        _id: id,
        username,
        email,
        password: await hash(password),
        lastLogin: new Date(),
        createdAt: new Date(),
        updatedAt: new Date(),
        research: [],
        mainPlanet
    }
    
    await (await Users()).insertOne(user);
    return user;
}

export const deleteUser = async (id: ObjectId) => {
    const users = await Users();
    return users.deleteOne({ _id: id });
}

export const getUserById = async (id: ObjectId) => {
    const users = await Users();
    return users.findOne({
        _id: id
    }) as Promise<DBUser | null>;
}

export const getUserByNickOrEmail = async (searchString: string) => {
    const users = await Users();
    return users.findOne({
        $or: [
            { username: searchString },
            { email: searchString }
        ]
    }) as Promise<DBUser | null>;
}

export const getUserByAccessToken = async(accessToken: string | AccessToken): Promise<DBUser | null> => {
    if(typeof accessToken === "string") {
        const userId = new ObjectId(Buffer.from(accessToken.split(".")[2], 'base64url').toString());
        return getUserById(userId);
    } else {
        const user = accessToken.user;
        if(!user) return null;
        return getUserById(user?.id);
    }
}

export const updateLastLogin = async (user: User) => {
    const users = await Users();
    return users.updateOne({ username: user.username }, { $set: { lastLogin: new Date() } });
}

export const getUserResearch = async (user: User): Promise<Array<{ id: string, level: number }>> => {
    const users = await Users();
    const rawUser = await users.findOne({ username: user.username });
    if (!rawUser) return [];
    return rawUser.research;
}

export const updateUserResearch = async (user: User, research: Array<{ id: string, level: number }>) => {
    const users = await Users();
    users.updateOne({ username: user.username }, { $set: { research } });
}