import { getHappening } from "./get-happening.js";
import { ok } from "../../is.js";
import { getAttendee } from "../attendee/index.js";
import { getPartner } from "../partner/index.js";
import { getOrganisation } from "../organisation/index.js";
import { getConfig } from "../../config/index.js";
export function createGetHappeningTreeContext(options = {}) {
    const { idKey = "happeningId", happenings, attendees, partners, organisations, get = getHappening } = options;
    const context = {
        idKey,
        get,
        trees: new Map(),
        store: happenings ?
            new Map(happenings.filter(Boolean).map(value => [value[idKey], value])) :
            undefined,
        attendees: attendees ?
            new Map(attendees.filter(Boolean).map(value => [value.attendeeId, value])) :
            new Map(),
        partners: partners ?
            new Map(partners.filter(Boolean).map(value => [value.partnerId, value])) :
            new Map(),
        organisations: organisations ?
            new Map(organisations.filter(Boolean).map(value => [value.organisationId, value])) :
            new Map()
    };
    ok(context);
    return context;
}
export async function getTopHappeningTree(happeningId) {
    const tree = await getHappeningTree(happeningId);
    const parent = getParent(tree);
    return getWithoutParent(parent);
    function getWithoutParent(tree) {
        return {
            ...tree,
            parent: undefined,
            children: tree.children.map(getWithoutParent)
        };
    }
    function getParent(tree) {
        const { parent } = tree;
        if (!parent)
            return tree;
        return getParent(parent);
    }
}
export async function getHappeningTree(happeningId, context = createGetHappeningTreeContext()) {
    const config = getConfig();
    if (config.getHappeningTree) {
        const tree = await config.getHappeningTree(happeningId, context);
        ok(tree, `Expected happening ${happeningId} to exist`);
        return tree;
    }
    const existing = context.trees.get(happeningId);
    if (existing)
        return existing;
    const happening = await getCachedHappening(happeningId);
    ok(happening, `Expected happening ${happeningId} to exist`);
    const { attendees, parent, children, ...data } = happening;
    const instance = {
        type: "happening",
        id: happeningId,
        ...data,
        children: [],
        attendees: []
    };
    instance.partner = instance.partner ?? await getCachedPartner(data.partnerId);
    instance.organisation = instance.organisation ?? await getCachedOrganisation(data.organisationId);
    // Put the instance in the memory cache so
    // it's object reference is used when
    context.trees.set(happeningId, instance);
    if (attendees?.length) {
        instance.attendees = (await Promise.all(attendees.map(attendee => getCachedAttendee(attendee))))
            .filter(Boolean);
    }
    // When getting the children trees, they will reference the parent using the above
    if (children?.length) {
        instance.children = await Promise.all(children.map(child => getHappeningTree(child, context)));
    }
    if (parent) {
        instance.parent = await getHappeningTree(parent, context);
    }
    return instance;
    async function getCachedHappening(happeningId) {
        const existing = context.store?.get(happeningId);
        if (existing)
            return existing;
        return context.get(happeningId);
    }
    async function getCachedAttendee(attendeeId) {
        if (!attendeeId)
            return undefined;
        const existing = context.attendees.get(attendeeId);
        if (existing)
            return existing;
        const value = await getAttendee(attendeeId);
        if (!value)
            return undefined;
        context.attendees.set(attendeeId, value);
        return value;
    }
    async function getCachedPartner(partnerId) {
        if (!partnerId)
            return undefined;
        const existing = context.partners.get(partnerId);
        if (existing)
            return existing;
        const value = await getPartner(partnerId);
        if (!value)
            return undefined;
        context.partners.set(partnerId, value);
        return value;
    }
    async function getCachedOrganisation(organisationId) {
        if (!organisationId)
            return undefined;
        const existing = context.organisations.get(organisationId);
        if (existing)
            return existing;
        const value = await getOrganisation(organisationId);
        if (!value)
            return undefined;
        context.organisations.set(organisationId, value);
        return value;
    }
}
//# sourceMappingURL=get-happening-tree.js.map