export function createEngineCompiledPlanService() {
    const records = new Map();
    let planByCompiled = new WeakMap();
    const planByTemplateId = new Map();
    let nextPlanId = 1;
    const releasePlanReference = (record) => {
        record.refCount -= 1;
        if (record.refCount > 0) {
            return;
        }
        records.delete(record.id);
        planByCompiled.delete(record.compiled);
        if (record.templateId !== undefined && planByTemplateId.get(record.templateId) === record) {
            planByTemplateId.delete(record.templateId);
        }
    };
    const setRecordTemplateId = (record, templateId) => {
        if (record.templateId !== undefined && record.templateId !== templateId && planByTemplateId.get(record.templateId) === record) {
            planByTemplateId.delete(record.templateId);
        }
        if (templateId !== undefined) {
            record.templateId = templateId;
            planByTemplateId.set(templateId, record);
        }
        else {
            delete record.templateId;
        }
    };
    return {
        intern(source, compiled, templateId) {
            if (templateId !== undefined) {
                const templatePlan = planByTemplateId.get(templateId);
                if (templatePlan?.compiled === compiled) {
                    templatePlan.refCount += 1;
                    templatePlan.source = source;
                    return templatePlan;
                }
            }
            const existing = planByCompiled.get(compiled);
            if (existing !== undefined) {
                existing.refCount += 1;
                existing.source = source;
                setRecordTemplateId(existing, templateId);
                return existing;
            }
            const record = {
                id: nextPlanId,
                source,
                compiled,
                ...(templateId !== undefined ? { templateId } : {}),
                refCount: 1,
            };
            nextPlanId += 1;
            records.set(record.id, record);
            planByCompiled.set(compiled, record);
            if (templateId !== undefined) {
                planByTemplateId.set(templateId, record);
            }
            return record;
        },
        replace(planId, source, compiled, templateId) {
            const existing = records.get(planId);
            if (!existing) {
                return this.intern(source, compiled, templateId);
            }
            if (existing.compiled === compiled) {
                existing.source = source;
                setRecordTemplateId(existing, templateId);
                return existing;
            }
            const alreadyInterned = planByCompiled.get(compiled);
            if (alreadyInterned && alreadyInterned !== existing) {
                releasePlanReference(existing);
                alreadyInterned.refCount += 1;
                alreadyInterned.source = source;
                setRecordTemplateId(alreadyInterned, templateId);
                return alreadyInterned;
            }
            if (existing.refCount === 1) {
                if (existing.templateId !== undefined && planByTemplateId.get(existing.templateId) === existing) {
                    planByTemplateId.delete(existing.templateId);
                }
                planByCompiled.delete(existing.compiled);
                existing.source = source;
                existing.compiled = compiled;
                setRecordTemplateId(existing, templateId);
                planByCompiled.set(compiled, existing);
                return existing;
            }
            releasePlanReference(existing);
            return this.intern(source, compiled, templateId);
        },
        isSoleOwner(planId, compiled) {
            const existing = records.get(planId);
            return existing?.compiled === compiled && existing.refCount === 1;
        },
        get(planId) {
            return records.get(planId);
        },
        release(planId) {
            const existing = records.get(planId);
            if (!existing) {
                return;
            }
            releasePlanReference(existing);
        },
        clear() {
            records.clear();
            planByCompiled = new WeakMap();
            planByTemplateId.clear();
            nextPlanId = 1;
        },
    };
}
//# sourceMappingURL=compiled-plan-service.js.map