/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Entity, world } from "@minecraft/server";
import { Server } from "./serverBuilder.js";
import { contentLog } from "./../Minecraft.js";
const objective = world.scoreboard.getObjective("GAMETEST_DB") ?? world.scoreboard.addObjective("GAMETEST_DB", "");
const databases = {};
export function getDatabase(name, provider = world, reviver, legacyStorage = false) {
    const key = name + "//" + (provider instanceof Entity ? provider.id : "world");
    if (!databases[key])
        databases[key] = new DatabaseImpl(name, provider, reviver, legacyStorage);
    return databases[key];
}
export function deleteDatabase(name, provider = world) {
    const key = name + "//" + (provider instanceof Entity ? provider.id : "world");
    if (databases[key])
        databases[key].clear();
    const scoreboardTable = DatabaseImpl.getScoreboardParticipant(DatabaseImpl.getScoreboardName(name, provider));
    if (scoreboardTable)
        objective.removeParticipant(scoreboardTable);
    else
        provider.setDynamicProperty(name, undefined);
}
class DatabaseImpl {
    constructor(name, provider = world, reviver, legacyStorage = false) {
        this.name = name;
        this.provider = provider;
        this.legacyStorage = legacyStorage;
        const scoreboardName = DatabaseImpl.getScoreboardName(name, provider);
        let table = DatabaseImpl.getScoreboardParticipant(scoreboardName);
        try {
            if (table)
                this.data = JSON.parse(JSON.parse(`"${table.displayName}"`), reviver)[1];
            else
                this.data = JSON.parse(provider.getDynamicProperty(name) ?? "{}", reviver);
            if (table && !legacyStorage)
                objective.removeParticipant(table);
        }
        catch {
            contentLog.error(`Failed to load database ${name} from ${provider instanceof Entity ? provider.nameTag ?? provider.id : "world"}`);
            if (table)
                objective.removeParticipant(table), (table = undefined);
            provider.setDynamicProperty(name, undefined);
            this.data = {};
        }
    }
    set(key, value) {
        this.data[key] = value;
    }
    get(key) {
        return this.data[key];
    }
    has(key) {
        return key in this.data;
    }
    delete(key) {
        delete this.data[key];
    }
    clear() {
        this.data = {};
    }
    save() {
        if (this.legacyStorage) {
            const scoreboardName = DatabaseImpl.getScoreboardName(this.name, this.provider);
            const table = DatabaseImpl.getScoreboardParticipant(scoreboardName);
            if (table)
                Server.runCommand(`scoreboard players reset "${table.displayName}" GAMETEST_DB`);
            Server.runCommand(`scoreboard players add ${JSON.stringify(JSON.stringify([scoreboardName, this.data]))} GAMETEST_DB 0`);
        }
        else {
            this.provider.setDynamicProperty(this.name, JSON.stringify(this.data));
        }
    }
    keys() {
        return Object.keys(this.data);
    }
    values() {
        return Object.values(this.data);
    }
    entries() {
        return Object.entries(this.data);
    }
    static getScoreboardParticipant(scoreboardName) {
        for (const table of objective?.getParticipants() ?? []) {
            if (table.displayName.startsWith(`[\\"${scoreboardName}\\"`))
                return table;
        }
    }
    static getScoreboardName(name, provider) {
        name = "wedit:" + name;
        if (provider instanceof Entity)
            name += provider.id;
        return name;
    }
}
