"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.errorTermsToMetadata = errorTermsToMetadata;
exports.extractErrorTerms = extractErrorTerms;
exports.toHttpError = toHttpError;
exports.createAggregateError = createAggregateError;
const RepresentationMetadata_1 = require("../../http/representation/RepresentationMetadata");
const TermUtil_1 = require("../TermUtil");
const Vocabularies_1 = require("../Vocabularies");
const BadRequestHttpError_1 = require("./BadRequestHttpError");
const ErrorUtil_1 = require("./ErrorUtil");
const HttpError_1 = require("./HttpError");
const InternalServerError_1 = require("./InternalServerError");
/**
 * Adds the given terms to error metadata.
 * The keys will be converted to predicates by prepending them with the `SOLID_ERROR_TERM` namespace.
 * The values will become literals.
 *
 * @param terms - Terms to add to the metadata.
 * @param metadata - Metadata to add the terms to. A new metadata object will be created if this is undefined.
 */
function errorTermsToMetadata(terms, metadata) {
    metadata = metadata ?? new RepresentationMetadata_1.RepresentationMetadata();
    for (const [key, value] of Object.entries(terms)) {
        if (value) {
            metadata.add((0, TermUtil_1.toPredicateTerm)(`${Vocabularies_1.SOLID_ERROR_TERM.namespace}${key}`), value);
        }
    }
    return metadata;
}
/**
 * Extracts all the error metadata terms and converts them to a simple object.
 * All predicates in the `SOLID_ERROR_TERM` namespace will be found.
 * The namespace will be removed from the predicate and the remainder will be used as a key.
 * The object literal values will be used as values in the resulting object.
 *
 * @param metadata - Metadata to extract the terms from.
 */
function extractErrorTerms(metadata) {
    const errorQuads = metadata.quads()
        .filter((quad) => quad.predicate.value.startsWith(Vocabularies_1.SOLID_ERROR_TERM.namespace));
    const errorTerms = {};
    for (const quad of errorQuads) {
        errorTerms[quad.predicate.value.slice(Vocabularies_1.SOLID_ERROR_TERM.namespace.length)] = quad.object.value;
    }
    return errorTerms;
}
/**
 * Converts an error in any shape to an {@link HttpError}.
 * For an {@link AggregateError} all the source errors will be combined
 * into a single HttpError with a status code that makes sense based on the sources.
 */
function toHttpError(error) {
    if (HttpError_1.HttpError.isInstance(error)) {
        return error;
    }
    if ((0, ErrorUtil_1.isError)(error)) {
        if (error instanceof AggregateError) {
            return createAggregateError(error.errors);
        }
        return new InternalServerError_1.InternalServerError(error.message);
    }
    return new InternalServerError_1.InternalServerError((0, ErrorUtil_1.createErrorMessage)(error));
}
/**
 * Combines a list of errors into a single HttpError.
 * Status code depends on the input errors. If they all share the same status code that code will be re-used.
 * If they are all within the 4xx range, 400 will be used, otherwise 500.
 *
 * @param errors - Errors to combine.
 */
function createAggregateError(errors) {
    const httpErrors = errors.map(toHttpError);
    const messages = httpErrors.map((error) => error.message).filter((msg) => msg.length > 0);
    // Let message depend on the messages that were present.
    // This prevents a bunch of empty strings being joined in the case most of them were 404s.
    let message;
    if (messages.length === 0) {
        message = '';
    }
    else if (messages.length === 1) {
        message = messages[0];
    }
    else {
        message = `Multiple handler errors: ${messages.join(', ')}`;
    }
    // Check if all errors have the same status code
    if (httpErrors.length > 0 && httpErrors.every((error) => error.statusCode === httpErrors[0].statusCode)) {
        return new HttpError_1.HttpError(httpErrors[0].statusCode, httpErrors[0].name, message);
    }
    // Find the error range (4xx or 5xx)
    if (httpErrors.some((error) => error.statusCode >= 500)) {
        return new InternalServerError_1.InternalServerError(message);
    }
    return new BadRequestHttpError_1.BadRequestHttpError(message);
}
//# sourceMappingURL=HttpErrorUtil.js.map