import { defineStore } from "pinia"
import type { MemberLight, Member } from "@shared/types/member"
import { getLightMembers, getFullMembers } from "@/api/member"
import { reactive, ref } from "vue"
import { resolve } from "path"
import { rejects } from "assert"

export const useMemberDirectory = defineStore('memberDirectory', () => {
    const light = reactive<Record<number, MemberLight>>({});
    const full = reactive<Record<number, Member>>({})

    function getLight(id: number): Promise<MemberLight> {
        if (light[id]) return Promise.resolve(light[id]);

        if (!lightWaiters.has(id)) {
            pendingLight.add(id);
            lightWaiters.set(id, []);
        }

        scheduleBatch();

        return new Promise<MemberLight>((resolve, reject) => {
            lightWaiters.get(id)!.push({ resolve, reject })
        })
    }

    function getFull(id: number): Promise<Member> {
        if (full[id]) return Promise.resolve(full[id])

        if (!fullWaiters.has(id)) {
            pendingFull.add(id)
            fullWaiters.set(id, [])
        }

        scheduleBatch()

        return new Promise<Member>((resolve, reject) => {
            fullWaiters.get(id)!.push({ resolve, reject })
        })
    }

    function invalidateMember(id: number) {
        delete light[id]
        delete full[id]
    }

    //batching system
    const pendingLight = new Set<number>()
    const pendingFull = new Set<number>()

    // promises
    const lightWaiters = new Map<number, Array<{ resolve: (m: MemberLight) => void; reject: (e: any) => void }>>()
    const fullWaiters = new Map<number, Array<{ resolve: (m: Member) => void; reject: (e: any) => void }>>()

    let batchTimer: ReturnType<typeof setTimeout> | null = null;

    function scheduleBatch() {
        if (batchTimer) return

        batchTimer = setTimeout(async () => {
            batchTimer = null;

            //Batch light
            if (pendingLight.size > 0) {
                const ids = Array.from(pendingLight);
                pendingLight.clear();

                try {
                    const res = await getLightMembers(ids);
                    for (const m of res) {
                        light[m.id] = m;

                        const waiters = lightWaiters.get(m.id);
                        if (waiters) {
                            for (const w of waiters) w.resolve(m)
                            lightWaiters.delete(m.id)
                        }
                    }

                    for (const id of ids) {
                        if (!light[id]) {
                            const waiters = lightWaiters.get(id);
                            if (waiters) {
                                for (const w of waiters) w.reject("Not found");
                                lightWaiters.delete(id);
                            }
                        }
                    }
                } catch (error) {
                    for (const id of ids) {
                        const waiters = lightWaiters.get(id);
                        if (waiters) {
                            for (const w of waiters) w.reject(error);
                            lightWaiters.delete(id);
                        }
                    }
                }
            }

            //batch full
            if (pendingFull.size > 0) {
                const ids = Array.from(pendingFull);
                pendingFull.clear();

                try {
                    const res = await getFullMembers(ids);
                    for (const m of res) {
                        full[m.member_id] = m;

                        const waiters = fullWaiters.get(m.member_id);
                        if (waiters) {
                            for (const w of waiters) w.resolve(m)
                            fullWaiters.delete(m.member_id);
                        }
                    }

                    for (const id of ids) {
                        if (!light[id]) {
                            const waiters = fullWaiters.get(id);
                            if (waiters) {
                                for (const w of waiters) w.reject("Not found");
                                fullWaiters.delete(id);
                            }
                        }
                    }
                } catch (error) {
                    for (const id of ids) {
                        const waiters = fullWaiters.get(id);
                        if (waiters) {
                            for (const w of waiters) w.reject(error);
                            fullWaiters.delete(id);
                        }
                    }
                }
            }
        })
    }

    return { light, full, getLight, getFull, invalidateMember }
})