import assert from 'assert';
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
import { merge } from 'lodash-es';
const defaultXmlCommonOptions = {
    ignoreAttributes: false,
    attributeNamePrefix: '@@',
    commentPropName: '#comment',
    parseAttributeValue: false,
};
const defaultXmlParserOptions = {
    ...defaultXmlCommonOptions,
};
const defaultXmlBuildOptions = {
    ...defaultXmlCommonOptions,
    suppressBooleanAttributes: false,
    suppressEmptyNode: true,
    format: true,
    indentBy: '    ',
};
export default class XmlStorage {
    sortFile;
    saveFile;
    loadFile;
    parser;
    builder;
    _cachedStore;
    constructor({ saveFile, loadFile, xmlParserOptions, xmlBuildOptions, sortFile, }) {
        assert(saveFile, 'saveFile callback is required to create a storage');
        assert(loadFile, 'loadFile callback is required to create a storage');
        this.parser = new XMLParser({ ...defaultXmlParserOptions, ...xmlParserOptions });
        this.builder = new XMLBuilder({ ...defaultXmlBuildOptions, ...xmlBuildOptions });
        this.saveFile = saveFile;
        this.loadFile = loadFile;
        this.sortFile = sortFile ?? true;
    }
    clearCache() {
        delete this._cachedStore;
    }
    save(sort = this.sortFile) {
        if (sort) {
            this.sort();
        }
        this.persist(false);
    }
    merge(source) {
        assert(typeof source === 'object', 'Storage `merge` method only accept objects');
        this._cachedStore = merge({}, this.store, source);
    }
    sort() { }
    persist(sort = this.sortFile) {
        if (this._cachedStore) {
            if (sort) {
                this.sort();
            }
            this.saveFile(this.builder.build(this._cachedStore));
        }
    }
    get store() {
        this.load();
        return this._cachedStore;
    }
    load() {
        if (!this._cachedStore) {
            this._cachedStore = this.parser.parse(this.loadFile());
        }
    }
    mergeContent(existing, newContent) {
        return newContent ? { ...existing, ...this.parser.parse(newContent) } : existing;
    }
}
