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());
    });
};
import { authenticate } from '../core/auth.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { RecordsDelete } from '../interfaces/records-delete.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { StorageController } from '../store/storage-controller.js';
import { DwnInterfaceName, DwnMethodName, Message } from '../core/message.js';
export class RecordsDeleteHandler {
    constructor(didResolver, messageStore, dataStore, eventLog) {
        this.didResolver = didResolver;
        this.messageStore = messageStore;
        this.dataStore = dataStore;
        this.eventLog = eventLog;
    }
    handle({ tenant, message }) {
        return __awaiter(this, void 0, void 0, function* () {
            let recordsDelete;
            try {
                recordsDelete = yield RecordsDelete.parse(message);
            }
            catch (e) {
                return messageReplyFromError(e, 400);
            }
            // authentication & authorization
            try {
                yield authenticate(message.authorization, this.didResolver);
                yield recordsDelete.authorize(tenant);
            }
            catch (e) {
                return messageReplyFromError(e, 401);
            }
            // get existing records matching the `recordId`
            const query = {
                interface: DwnInterfaceName.Records,
                recordId: message.descriptor.recordId
            };
            const existingMessages = yield this.messageStore.query(tenant, query);
            // find which message is the newest, and if the incoming message is the newest
            const newestExistingMessage = yield RecordsWrite.getNewestMessage(existingMessages);
            let incomingMessageIsNewest = false;
            let newestMessage;
            // if incoming message is newest
            if (newestExistingMessage === undefined || (yield RecordsWrite.isNewer(message, newestExistingMessage))) {
                incomingMessageIsNewest = true;
                newestMessage = message;
            }
            else { // existing message is the same age or newer than the incoming message
                newestMessage = newestExistingMessage;
            }
            if (!incomingMessageIsNewest) {
                return {
                    status: { code: 409, detail: 'Conflict' }
                };
            }
            // return Not Found if record does not exist or is already deleted
            if (newestExistingMessage === undefined || newestExistingMessage.descriptor.method === DwnMethodName.Delete) {
                return {
                    status: { code: 404, detail: 'Not Found' }
                };
            }
            const indexes = yield constructIndexes(tenant, recordsDelete);
            yield this.messageStore.put(tenant, message, indexes);
            const messageCid = yield Message.getCid(message);
            yield this.eventLog.append(tenant, messageCid);
            // delete all existing messages that are not newest, except for the initial write
            yield StorageController.deleteAllOlderMessagesButKeepInitialWrite(tenant, existingMessages, newestMessage, this.messageStore, this.dataStore, this.eventLog);
            const messageReply = {
                status: { code: 202, detail: 'Accepted' }
            };
            return messageReply;
        });
    }
    ;
}
export function constructIndexes(tenant, recordsDelete) {
    return __awaiter(this, void 0, void 0, function* () {
        const message = recordsDelete.message;
        const descriptor = Object.assign({}, message.descriptor);
        // NOTE: the "trick" not may not be apparent on how a query is able to omit deleted records:
        // we intentionally not add index for `isLatestBaseState` at all, this means that upon a successful delete,
        // no messages with the record ID will match any query because queries by design filter by `isLatestBaseState = true`,
        // `isLatestBaseState` for the initial delete would have been toggled to `false`
        const indexes = Object.assign({ 
            // isLatestBaseState : "true", // intentionally showing that this index is omitted
            author: recordsDelete.author }, descriptor);
        return indexes;
    });
}
//# sourceMappingURL=records-delete.js.map