"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractGithubGraphqlCacheStrategy = void 0;
const luxon_1 = require("luxon");
const util_1 = require("../util");
/**
 * Cache strategy handles the caching Github GraphQL items
 * and reconciling them with newly obtained ones from paginated queries.
 */
class AbstractGithubGraphqlCacheStrategy {
    constructor(cacheNs, cacheKey) {
        this.cacheNs = cacheNs;
        this.cacheKey = cacheKey;
        /**
         * The time which is used during single cache access cycle.
         */
        this.now = luxon_1.DateTime.now();
        /**
         * Set of all versions which were reconciled
         * during the current cache access cycle.
         */
        this.reconciledVersions = new Set();
        this.createdAt = this.now;
        this.updatedAt = this.now;
    }
    /**
     * Load data previously persisted by this strategy
     * for given `cacheNs` and `cacheKey`.
     */
    async getItems() {
        if (this.items) {
            return this.items;
        }
        let result = {
            items: {},
            createdAt: this.createdAt.toISO(),
            updatedAt: this.updatedAt.toISO(),
        };
        const storedData = await this.load();
        if (storedData) {
            const cacheTTLDuration = {
                days: AbstractGithubGraphqlCacheStrategy.cacheTTLDays,
            };
            if (!(0, util_1.isDateExpired)(this.now, storedData.createdAt, cacheTTLDuration)) {
                result = storedData;
            }
        }
        this.createdAt = luxon_1.DateTime.fromISO(result.createdAt);
        this.updatedAt = luxon_1.DateTime.fromISO(result.updatedAt);
        this.items = result.items;
        return this.items;
    }
    /**
     * If package release exists longer than this cache can exist,
     * we assume it won't updated/removed on the Github side.
     */
    isStabilized(item) {
        const unstableDuration = {
            days: AbstractGithubGraphqlCacheStrategy.cacheTTLDays,
        };
        return (0, util_1.isDateExpired)(this.now, item.releaseTimestamp, unstableDuration);
    }
    /**
     * Process items received from GraphQL page
     * ordered by `releaseTimestamp` in descending order
     * (fresh versions go first).
     */
    async reconcile(items) {
        const cachedItems = await this.getItems();
        let isPaginationDone = false;
        for (const item of items) {
            const { version } = item;
            // If we reached previously stored item that is stabilized,
            // we assume the further pagination will not yield any new items.
            const oldItem = cachedItems[version];
            if (oldItem && this.isStabilized(oldItem)) {
                isPaginationDone = true;
                break;
            }
            cachedItems[version] = item;
            this.reconciledVersions.add(version);
        }
        this.items = cachedItems;
        return isPaginationDone;
    }
    /**
     * Handle removed items for packages that are not stabilized
     * and return the list of all items.
     */
    async finalize() {
        const cachedItems = await this.getItems();
        const resultItems = {};
        for (const [version, item] of Object.entries(cachedItems)) {
            if (this.isStabilized(item) || this.reconciledVersions.has(version)) {
                resultItems[version] = item;
            }
        }
        await this.store(resultItems);
        return Object.values(resultItems);
    }
    /**
     * Update `updatedAt` field and persist the data.
     */
    async store(cachedItems) {
        const cacheRecord = {
            items: cachedItems,
            createdAt: this.createdAt.toISO(),
            updatedAt: this.now.toISO(),
        };
        await this.persist(cacheRecord);
    }
}
exports.AbstractGithubGraphqlCacheStrategy = AbstractGithubGraphqlCacheStrategy;
/**
 * Time period after which a cache record is considered expired.
 */
AbstractGithubGraphqlCacheStrategy.cacheTTLDays = 30;
//# sourceMappingURL=abstract-cache-strategy.js.map