import { eq, SQL, type Operators } from 'drizzle-orm';
import useDatabase from '~/composables/useDatabase';
import { characterTable, userPermissionsTable } from '~/db/schema';
import { hasPermissions } from '~/shared/auth.util';
import { group } from '~/shared/general.util';
import type { Character, MainStat, TrainingLevel } from '~/types/character';

export default defineEventHandler(async (e) => {
    let { visibility } = getQuery(e) as { visibility?: "public" | "own" | "admin" };

    if(!visibility)
    {
        visibility = "own";
    }

    let where: ((character: typeof characterTable._.config.columns, sql: Operators) => SQL | undefined) | undefined = undefined;
    const db = useDatabase();

    const session = await getUserSession(e);
    if(visibility === "own")
    {
        if(!session.user)
        {
            setResponseStatus(e, 401);
            return;
        }

        where = (character, { eq, and }) => and(eq(character.owner, session.user!.id));
    }
    else if(visibility === 'public')
    {
        where = (character, { eq, and }) => eq(character.visibility, "public");
    }
    else if(visibility === 'admin')
    {
        if(!session.user)
        {
            setResponseStatus(e, 401);
            return;
        }
        const db = useDatabase();

        const rights = db.select({ right: userPermissionsTable.permission }).from(userPermissionsTable).where(eq(userPermissionsTable.id, session.user.id)).all();
        if(rights.length === 0 || !hasPermissions(rights.map(e => e.right), ['admin']))
        {
            setResponseStatus(e, 403);
            return;
        }

        where = undefined;
    }
    
    const characters = db.query.characterTable.findMany({
        with: {
            abilities: true,
            levels: true,
            training: true,
            choices: true,
            user: {
                columns: { username: true }
            }
        },
        where: where,
    }).sync();

    if(characters !== undefined)
    {
        return characters.map(character => ({
            id: character.id,

            name: character.name,
            people: character.people,
            level: character.level,
            aspect: character.aspect,
            notes: { public: character.public_notes, private: session.user?.id === character.owner ? character.private_notes : undefined },
            variables: character.variables,

            training: character.training.reduce((p, v) => { p[v.stat] ??= {}; p[v.stat][v.level as TrainingLevel] = v.choice; return p; }, {} as Record<MainStat, Partial<Record<TrainingLevel, number>>>),
            leveling: group(character.levels, "level", "choice"),
            abilities: group(character.abilities, "ability", "value"),
            choices: character.choices.reduce((p, v) => { p[v.id] ??= []; p[v.id]?.push(v.choice); return p; }, {} as Record<string, number[]>),

            owner: character.owner,
            username: character.user.username,
            visibility: character.visibility,
        } as Character));
    }
    
    setResponseStatus(e, 404);
    return;
});