import GLib from 'gi://GLib';
import { ClipboardHistory } from '../common/constants.js';
import { ClipboardEntry } from './database.js';
/**
 * In memory database
 */
export class MemoryDatabase {
    _entries = new Map();
    _keys = new Map();
    _id = 0;
    constructor() { }
    async init() { }
    clear(history) {
        let deleted = [];
        switch (history) {
            case ClipboardHistory.Clear:
                deleted = Array.from(this._keys.keys());
                this._entries.clear();
                this._keys.clear();
                break;
            case ClipboardHistory.KeepPinnedAndTagged:
                deleted = [];
                for (const [key, entry] of this._entries) {
                    if (!(entry.pinned || entry.tag)) {
                        this._entries.delete(key);
                        this._keys.delete(entry.id);
                        deleted.push(entry.id);
                    }
                }
                break;
            case ClipboardHistory.KeepAll:
                break;
        }
        return Promise.resolve(deleted);
    }
    async close() {
        await this.clear(ClipboardHistory.Clear);
    }
    entries() {
        const entries = Array.from(this._entries.values()).sort((a, b) => b.datetime.compare(a.datetime));
        return Promise.resolve(entries);
    }
    selectConflict(entry) {
        const key = this.entryToKey(entry);
        return Promise.resolve(this._entries.get(key)?.id ?? null);
    }
    insert(type, content, metadata = null) {
        const key = this.entryToKey({ type, content });
        const entry = this._entries.get(key);
        if (entry) {
            return Promise.resolve(null);
        }
        else {
            const newEntry = new ClipboardEntry(this._id++, type, content, false, null, GLib.DateTime.new_now_utc(), metadata);
            this._entries.set(key, newEntry);
            this._keys.set(newEntry.id, key);
            return Promise.resolve(newEntry);
        }
    }
    updateProperty(entry, property) {
        if (property !== 'content')
            return Promise.resolve(-1);
        const key = this.entryToKey(entry);
        const existingEntry = this._entries.get(key);
        if (existingEntry) {
            return Promise.resolve(existingEntry.id);
        }
        else {
            const prevKey = this._keys.get(entry.id);
            if (prevKey)
                this._entries.delete(prevKey);
            this._entries.set(key, entry);
            this._keys.set(entry.id, key);
            return Promise.resolve(-1);
        }
    }
    delete(entry) {
        const key = this._keys.get(entry.id);
        this._keys.delete(entry.id);
        if (key) {
            this._entries.delete(key);
            return Promise.resolve(true);
        }
        return Promise.resolve(false);
    }
    async deleteOldest(offset, olderThanMinutes) {
        const entries = await this.entries();
        let deleted = entries
            .filter((e) => !(e.pinned || e.tag))
            .map((e) => e.id)
            .slice(offset);
        if (olderThanMinutes > 0) {
            const now = GLib.DateTime.new_now_utc();
            const olderThan = now.add_minutes(-olderThanMinutes);
            deleted = [
                ...new Set([
                    ...deleted,
                    ...entries
                        .filter((e) => !(e.pinned || e.tag) && e.datetime.compare(olderThan) < 0)
                        .map((e) => e.id),
                ]),
            ];
        }
        for (const id of deleted) {
            const key = this._keys.get(id);
            this._keys.delete(id);
            if (key)
                this._entries.delete(key);
        }
        return deleted;
    }
    entryToKey(entry) {
        return `${entry.type}:${entry.content}`;
    }
}
