import useDatabase from '~/composables/useDatabase';
import { schema } from '~/schemas/login';
import type { UserSession, UserSessionRequired } from '~/types/auth';
import { ZodError } from 'zod';
import { checkSession, logSession } from '~/server/utils/user';
import { usersDataTable, usersTable } from '~/db/schema';
import { eq, or, sql } from 'drizzle-orm';

interface SuccessHandler
{
    success: true;
    session: UserSession;
}
interface ErrorHandler
{
    success: false;
    error: Error | ZodError<{
        usernameOrEmail: string;
        password: string;
    }>;
}
type Return = SuccessHandler | ErrorHandler;

export default defineEventHandler(async (e): Promise<Return> => {
    try
    {
        const session = await getUserSession(e);
        const db = useDatabase();

        const checkedSession = await checkSession(e, session);

        if(checkedSession !== undefined)
            return checkedSession;

        const body = await readValidatedBody(e, schema.safeParse);

        if (!body.success)
        {
            await clearUserSession(e);

            setResponseStatus(e, 406);
            return { success: false, error: body.error };
        }

        const hash = await Bun.password.hash(body.data.password);
        const id = db.select({ id: usersTable.id, hash: usersTable.hash }).from(usersTable).where(or(eq(usersTable.username, sql.placeholder('username')), eq(usersTable.email, sql.placeholder('username')))).prepare().get({ username: body.data.usernameOrEmail });

        if(!id || !id.id || !id.hash)
        {
            await clearUserSession(e);

            setResponseStatus(e, 401);
            return { success: false, error: new ZodError([{ code: 'custom', path: ['username'], message: 'Identifiant inconnu' }]) };
        }
        
        const valid = await Bun.password.verify(body.data.password, id.hash);

        if(!valid)
        {
            await clearUserSession(e);

            setResponseStatus(e, 401);
            return { success: false, error: new ZodError([{ code: 'custom', path: ['password'], message: 'Mot de passe incorrect' }]) };
        }

        const user = db.query.usersTable.findFirst({
            columns: {
                id: true,
                email: true,
                username: true,
                state: true,
            },
            with: {
                data: true,
                permission: true,
            },
            where: (table) => eq(table.id, sql.placeholder('id'))
        }).prepare().get({ id: id.id });

        if(!user)
        {
            setResponseStatus(e, 401);
            return { success: false, error: new Error('Données utilisateur introuvable') };
        }

        const data = logSession(e, await setUserSession(e, { 
            user: {
                ...user.data,
                email: user.email,
                username: user.username,
                state: user.state,
                permissions: user.permission.map(e => e.permission),
            }
        }) as UserSessionRequired);

        setResponseStatus(e, 201);
        return { success: true, session: data };
    }
    catch(err: any)
    {
        console.error(err);

        await clearUserSession(e);
        return { success: false, error: err as Error };
    }
});