import fs from"node:fs";import{ClassicLevel}from"classic-level";import SublevelDatabase from"./sublevel-database.mjs";import Semaphore from"../../../common/utils/semaphore.mjs";export default class LevelDatabase extends ClassicLevel{constructor(e,a,t={}){if(!e||!a)throw new Error("You must provide a unique database name and file path location");if(LevelDatabase.#e.has(e))throw new Error(`The database "${e}" is already open and cannot be re-created.`);t.keyEncoding="utf8",t.valueEncoding="json",super(a,t),this.#a=e,LevelDatabase.#e.set(e,this);const s=t.sublevels||[];this.setMaxListeners(Math.max(10,s.length+1));const n={keyEncoding:t.keyEncoding,valueEncoding:t.valueEncoding};for(const e of s)this.#t[e]=this.sublevel(e,n)}static async connect(e,a,{allowRepair:t=!0,...s}={}){const n=new this(e,a,{createIfMissing:!0,...s});try{await n.open({passive:!0}),await n.keys().all(),global.logger.info(`Connected to database "${e}"`)}catch(o){if(await n.close(),o.message=`Failed to connect to database "${e}": ${o.message}`,t)return logger.error(o),LevelDatabase.#s(e,a,s);throw o}return n}static async#s(e,a,t){return logger.warn(`FoundryVTT | Attempting database repair for ${a}`),await this.repair(a),logger.warn(`FoundryVTT | Repair of ${a} complete. Attempting re-connection`),LevelDatabase.connect(e,a,{allowRepair:!1,...t})}semaphore=new Semaphore(1);get name(){return this.#a}#a;get sublevels(){return this.#t}#t={};static get databases(){return LevelDatabase.#e}static#e=new Map;static formatKey(...e){return e.join(".")}async close(...e){if(LevelDatabase.#e.delete(this.#a),"open"===this.status)try{await this.compactFull()}catch(e){e.message=`Unable to compact database ${this.location}: ${e.message}`,logger.error(e)}return super.close(...e)}async clone(e,a){if(this.constructor.databases.has(e)||a===this.location)throw new Error("The cloned database name and location must be unique");const t=await this.constructor.connect(e,a,{sublevels:Object.keys(this.sublevels)}),s=t.batch(),n=this.iterator();for await(const[e,a]of n)s.put(e,a);return await n.close(),await s.write(),t}async destroy(){await this.close(),fs.rmSync(this.location,{recursive:!0})}async compactFull(){const e=this.keys({limit:1,fillCache:!1}),a=await e.next();await e.close();const t=this.keys({limit:1,reverse:!0,fillCache:!1}),s=await t.next();return await t.close(),this.compactRange(a,s,{keyEncoding:"utf8"})}async size(){const e=this.keys({limit:1,fillCache:!1}),a=await e.next();await e.close();const t=this.keys({limit:1,reverse:!0,fillCache:!1}),s=await t.next();return await t.close(),this.approximateSize(a,s,{keyEncoding:"utf8"})}_sublevel(e,a){return new SublevelDatabase(this,e,a)}}