"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());
    });
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RecordsReadHandler = void 0;
const auth_js_1 = require("../core/auth.js");
const message_js_1 = require("../core/message.js");
const message_reply_js_1 = require("../core/message-reply.js");
const records_read_js_1 = require("../interfaces/records-read.js");
const records_write_js_1 = require("../interfaces/records-write.js");
const message_js_2 = require("../core/message.js");
class RecordsReadHandler {
    constructor(didResolver, messageStore, dataStore) {
        this.didResolver = didResolver;
        this.messageStore = messageStore;
        this.dataStore = dataStore;
    }
    handle({ tenant, message }) {
        return __awaiter(this, void 0, void 0, function* () {
            let recordsRead;
            try {
                recordsRead = yield records_read_js_1.RecordsRead.parse(message);
            }
            catch (e) {
                return (0, message_reply_js_1.messageReplyFromError)(e, 400);
            }
            // authentication
            try {
                if (recordsRead.author !== undefined) {
                    yield (0, auth_js_1.authenticate)(message.authorization, this.didResolver);
                }
            }
            catch (e) {
                return (0, message_reply_js_1.messageReplyFromError)(e, 401);
            }
            // get existing messages matching `recordId` so we can perform authorization
            const query = {
                interface: message_js_2.DwnInterfaceName.Records,
                recordId: message.descriptor.recordId
            };
            const existingMessages = yield this.messageStore.query(tenant, query);
            const newestExistingMessage = yield records_write_js_1.RecordsWrite.getNewestMessage(existingMessages);
            // if no record found or it has been deleted
            if (newestExistingMessage === undefined || newestExistingMessage.descriptor.method === message_js_2.DwnMethodName.Delete) {
                return {
                    status: { code: 404, detail: 'Not Found' }
                };
            }
            const newestRecordsWrite = newestExistingMessage;
            try {
                yield recordsRead.authorize(tenant, yield records_write_js_1.RecordsWrite.parse(newestRecordsWrite), this.messageStore);
            }
            catch (error) {
                return (0, message_reply_js_1.messageReplyFromError)(error, 401);
            }
            const messageCid = yield message_js_1.Message.getCid(newestRecordsWrite);
            const result = yield this.dataStore.get(tenant, messageCid, newestRecordsWrite.descriptor.dataCid);
            if ((result === null || result === void 0 ? void 0 : result.dataStream) === undefined) {
                return {
                    status: { code: 404, detail: 'Not Found' }
                };
            }
            const { authorization: _ } = newestRecordsWrite, recordsWriteWithoutAuthorization = __rest(newestRecordsWrite, ["authorization"]); // a trick to stripping away `authorization`
            const messageReply = {
                status: { code: 200, detail: 'OK' },
                record: Object.assign(Object.assign({}, recordsWriteWithoutAuthorization), { data: result.dataStream })
            };
            return messageReply;
        });
    }
    ;
}
exports.RecordsReadHandler = RecordsReadHandler;
//# sourceMappingURL=records-read.js.map