"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StorageController = void 0;
const records_write_js_1 = require("../handlers/records-write.js");
const data_stream_js_1 = require("../utils/data-stream.js");
const dwn_constant_js_1 = require("../core/dwn-constant.js");
const encoder_js_1 = require("../utils/encoder.js");
const records_write_js_2 = require("../interfaces/records-write.js");
const message_js_1 = require("../core/message.js");
/**
 * A class that provides an abstraction for the usage of MessageStore, DataStore, and EventLog.
 */
class StorageController {
    static query(messageStore, dataStore, tenant, filter) {
        return __awaiter(this, void 0, void 0, function* () {
            const messages = (yield messageStore.query(tenant, filter));
            // for every message, only include the data as `encodedData` if the data size is equal or smaller than the size threshold
            for (const message of messages) {
                const dataCid = message.descriptor.dataCid;
                const dataSize = message.descriptor.dataSize;
                if (dataCid !== undefined && dataSize <= dwn_constant_js_1.DwnConstant.maxDataSizeAllowedToBeEncoded) {
                    const messageCid = yield message_js_1.Message.getCid(message);
                    const result = yield dataStore.get(tenant, messageCid, dataCid);
                    if (result) {
                        const dataBytes = yield data_stream_js_1.DataStream.toBytes(result.dataStream);
                        message.encodedData = encoder_js_1.Encoder.bytesToBase64Url(dataBytes);
                    }
                }
            }
            return messages;
        });
    }
    /**
     * Deletes a message.
     */
    static delete(messageStore, dataStore, tenant, message) {
        return __awaiter(this, void 0, void 0, function* () {
            const messageCid = yield message_js_1.Message.getCid(message);
            if (message.descriptor.method === message_js_1.DwnMethodName.Write) {
                const recordsWriteMessage = message;
                yield dataStore.delete(tenant, messageCid, recordsWriteMessage.descriptor.dataCid);
            }
            yield messageStore.delete(tenant, messageCid);
        });
    }
    /**
     * Deletes all messages in `existingMessages` that are older than the `comparedToMessage` in the given tenant,
     * but keep the initial write write for future processing by ensuring its `isLatestBaseState` index is "false".
     */
    static deleteAllOlderMessagesButKeepInitialWrite(tenant, existingMessages, comparedToMessage, messageStore, dataStore, eventLog) {
        return __awaiter(this, void 0, void 0, function* () {
            const deletedMessageCids = [];
            // NOTE: under normal operation, there should only be at most two existing records per `recordId` (initial + a potential subsequent write/delete),
            // but the DWN may crash before `delete()` is called below, so we use a loop as a tactic to clean up lingering data as needed
            for (const message of existingMessages) {
                const messageIsOld = yield message_js_1.Message.isOlder(message, comparedToMessage);
                if (messageIsOld) {
                    // the easiest implementation here is delete each old messages
                    // and re-create it with the right index (isLatestBaseState = 'false') if the message is the initial write,
                    // but there is room for better/more efficient implementation here
                    yield StorageController.delete(messageStore, dataStore, tenant, message);
                    // if the existing message is the initial write
                    // we actually need to keep it BUT, need to ensure the message is no longer marked as the latest state
                    const existingMessageIsInitialWrite = yield records_write_js_2.RecordsWrite.isInitialWrite(message);
                    if (existingMessageIsInitialWrite) {
                        const existingRecordsWrite = yield records_write_js_2.RecordsWrite.parse(message);
                        const isLatestBaseState = false;
                        const indexes = yield (0, records_write_js_1.constructRecordsWriteIndexes)(existingRecordsWrite, isLatestBaseState);
                        yield messageStore.put(tenant, message, indexes);
                    }
                    else {
                        const messageCid = yield message_js_1.Message.getCid(message);
                        deletedMessageCids.push(messageCid);
                    }
                }
                yield eventLog.deleteEventsByCid(tenant, deletedMessageCids);
            }
        });
    }
}
exports.StorageController = StorageController;
//# sourceMappingURL=storage-controller.js.map