"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
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.ExtendedMessageManager = exports.ExtendedMessageMetadata = void 0;
const constants_1 = require("./constants");
const client_s3_1 = require("@aws-sdk/client-s3");
const credential_providers_1 = require("@aws-sdk/credential-providers");
const jackson_js_1 = require("jackson-js");
const client_s3_2 = require("@aws-sdk/client-s3");
const error_1 = require("../error");
const logger_1 = require("../logger");
const jack_x_1 = require("../jack-x");
class ExtendedMessageMetadata {
    constructor(version) {
        this.version = version;
        this.schema = new Map();
        this.tags = new Map();
        this.references = new Map();
    }
    addSchema(key, value) {
        this.schema.set(key, value);
    }
    addTags(key, value) {
        this.tags.set(key, value);
    }
    addReference(key, value) {
        this.references.set(key, value);
    }
    getSchemaKeys() {
        return Array.from(this.schema.keys());
    }
    getSchemaEntries(key) {
        const entries = this.schema.get(key);
        if (undefined == entries) {
            return new Array();
        }
        if (this.version == constants_1.MetadataVersion.V1) {
            return entries;
        }
        return new Array();
    }
    getTags(key) {
        return this.tags.get(key);
    }
    getReference(key) {
        return this.references.get(key);
    }
}
__decorate([
    (0, jackson_js_1.JsonProperty)()
], ExtendedMessageMetadata.prototype, "version", void 0);
__decorate([
    (0, jackson_js_1.JsonProperty)(),
    (0, jackson_js_1.JsonClassType)({ type: () => [(Map)] })
], ExtendedMessageMetadata.prototype, "schema", void 0);
__decorate([
    (0, jackson_js_1.JsonProperty)(),
    (0, jackson_js_1.JsonClassType)({ type: () => [(Map)] })
], ExtendedMessageMetadata.prototype, "tags", void 0);
__decorate([
    (0, jackson_js_1.JsonProperty)(),
    (0, jackson_js_1.JsonClassType)({ type: () => [(Map)] })
], ExtendedMessageMetadata.prototype, "references", void 0);
exports.ExtendedMessageMetadata = ExtendedMessageMetadata;
class ExtendedMessageManager {
    constructor(config) {
        const settings = {
            credentials: (0, credential_providers_1.fromNodeProviderChain)(),
            region: config.region
        };
        this.s3 = new client_s3_1.S3Client(settings);
        this.bucket = config.bucket;
    }
    getRaw(ctx, bucket, reference) {
        return __awaiter(this, void 0, void 0, function* () {
            const params = {
                Bucket: bucket,
                Key: reference,
            };
            const command = new client_s3_1.GetObjectCommand(params);
            const ret = yield this.s3.send(command)
                .catch((error) => {
                (0, logger_1.getLogger)(ctx).withError(new Error(error)).with({
                    bucket: bucket,
                    reference: reference,
                }).error("could not retrieve message data");
                return error;
            });
            if (ret instanceof Error) {
                return ret;
            }
            if (!ret || !ret.Body) {
                return undefined;
            }
            return ret.Body;
        });
    }
    getRawString(ctx, bucket, reference) {
        return __awaiter(this, void 0, void 0, function* () {
            const body = yield this.getRaw(ctx, bucket, reference);
            if (body instanceof Error) {
                if (body instanceof client_s3_2.NotFound) {
                    return new error_1.FatalError(body);
                }
                return new error_1.RetriableError(body);
            }
            return yield (body === null || body === void 0 ? void 0 : body.transformToString());
        });
    }
    getRawBytes(ctx, bucket, reference) {
        return __awaiter(this, void 0, void 0, function* () {
            const body = yield this.getRaw(ctx, bucket, reference);
            if (body instanceof Error) {
                return body;
            }
            return yield (body === null || body === void 0 ? void 0 : body.transformToByteArray());
        });
    }
    get(ctx, creatorClass, bucket, reference, isArray = false) {
        return __awaiter(this, void 0, void 0, function* () {
            const bodyString = yield this.getRawString(ctx, bucket, reference);
            if (bodyString instanceof Error) {
                return bodyString;
            }
            if (bodyString == undefined) {
                return undefined;
            }
            const parser = new jackson_js_1.JsonParser();
            return parser.parse(bodyString, {
                mainCreator: () => isArray ? [Array, [creatorClass]] : [creatorClass],
                features: {
                    deserialization: {
                        FAIL_ON_UNKNOWN_PROPERTIES: false
                    }
                }
            });
        });
    }
    put(ctx, metadataReference, metadata, payloads) {
        return __awaiter(this, void 0, void 0, function* () {
            const logger = (0, logger_1.getLogger)(ctx).with({
                bucket: this.bucket,
                reference: metadataReference,
            });
            const params = {
                Bucket: this.bucket,
                Key: metadataReference,
                Body: (0, jack_x_1.serialize)(metadata),
            };
            const command = new client_s3_1.PutObjectCommand(params);
            const res = yield this.s3.send(command).catch((error) => {
                logger.withError(new Error(error)).error("could not put message metadata");
                return Promise.reject(new Error(error));
            });
            if (!res) {
                return undefined;
            }
            const promises = new Array();
            payloads.forEach(payloads => {
                const params = {
                    Bucket: this.bucket,
                    Key: payloads.reference,
                    Body: (0, jack_x_1.serialize)(payloads.data),
                };
                const command = new client_s3_1.PutObjectCommand(params);
                promises.push(this.s3.send(command).catch((error) => {
                    return error;
                }));
            });
            yield Promise.all(promises).catch((error) => {
                logger.withError(new Error(error)).error("could not put message playloads");
                return Promise.reject(new Error(error));
            });
            return {
                metadataReference: metadataReference,
                bucket: this.bucket,
            };
        });
    }
}
exports.ExtendedMessageManager = ExtendedMessageManager;
//# sourceMappingURL=extended-message.js.map