"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DistributedPersistence = void 0;
const various_1 = require("./various");
/**
 * For internal use. Helper class for {@link DistributedPersistence}.
 */
class DistributedPersistable {
    constructor(persistence, partitionKey, sortKey, value) {
        this._changed = false;
        this.persistence = persistence;
        this.partitionKey = partitionKey;
        this.sortKey = sortKey;
        this.value = value;
    }
    async load() {
        const result = await this.persistence.loadImpl(this.partitionKey, this.sortKey);
        if (result[0] !== undefined) {
            this.value = result[0];
        }
        this.version = result[1];
        this._changed = false;
        return result[0];
    }
    async store(force) {
        if (!force) {
            if (!this._changed) {
                return;
            }
        }
        if (this._changed) {
            if (this.version) {
                const next = parseInt(this.version || '0') + 1;
                this.version = next.toString().padStart(20, '0');
            }
            else {
                const next = Date.now();
                this.version = next.toString().padStart(20, '0');
            }
        }
        await this.persistence.storeImpl(this.partitionKey, this.sortKey, this.value, this.version);
        this._changed = false;
    }
    change(value) {
        if (value !== undefined) {
            this.value = value;
        }
        this._changed = true;
    }
    clear() {
        this.value = undefined;
        this._changed = true;
    }
    changed() {
        return this._changed;
    }
}
/**
 * Implementation of {@link IPersistence} that uses a distributed persistence service (like the one defined
 * in {@link @darlean/fs-persistence-suite}) to provide persistency.
 */
class DistributedPersistence {
    constructor(service, deser, specifiers) {
        this.service = service;
        this.deser = deser;
        this.specifiers = specifiers;
    }
    persistable(partitionKey, sortKey, value) {
        return new DistributedPersistable(this, partitionKey, sortKey, value);
    }
    async load(partitionKey, sortKey) {
        const result = this.persistable(partitionKey, sortKey, undefined);
        await result.load();
        return result;
    }
    async loadImpl(partitionKey, sortKey) {
        const result = await this.service.load({
            specifiers: this.specifiers,
            partitionKey: partitionKey ?? [],
            sortKey: sortKey ?? []
        });
        if (result.value) {
            const value = this.deser.deserialize(result.value);
            return [value, result.version];
        }
        return [undefined, result.version];
    }
    async storeImpl(partitionKey, sortKey, value, version) {
        const v = this.deser.serialize(value);
        await this.service.store({
            specifiers: this.specifiers,
            partitionKey: partitionKey ?? [],
            sortKey: sortKey ?? [],
            value: v,
            version: version
        });
    }
    sub(partitionKey, sortKey) {
        return new various_1.SubPersistence(this, partitionKey, sortKey);
    }
}
exports.DistributedPersistence = DistributedPersistence;
