/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */

export type RespondMessage = {
    statusMessage?: string,
    statusCode?: number,
    data?: any
};

export type RespondErrorMessage = {
    statusMessage?: string,
    statusCode?: number,
    message?: string,
    code?: string
}

export default function responseMiddleware(request: any, response: any, next: any) {
    const defaultErrorCode = 'service_error';
    const defaultErrorMessage = 'The service encountered an unknown error, which prevented it from fulfilling the request.';

    response.respond = (message?: RespondMessage) => {
        if(message) {
            if (message.data == null && message.statusCode == null) {
                message.statusCode = 204;
            } else {
                message.statusCode = message.statusCode == null ? 200 : message.statusCode;
            }

            if (message.data !== null) response.json(message.data);
        } else {
            message = {
                statusCode: 204
            }
        }

        response.status(message.statusCode);

        return response.end();
    };

    response.respondException = (message?: RespondErrorMessage) => {
        if(message) {
            message.code = message.code === undefined ? defaultErrorCode : message.code;
            message.message = message.message === undefined ? defaultErrorMessage : message.message;

            message.statusCode = message.statusCode === undefined ? 500 : message.statusCode;
        } else {
            message = {
                code: defaultErrorCode,
                message: defaultErrorMessage,
                statusCode: 500
            }
        }

        response.status(message.statusCode);

        const data: object = {
            message: message.message,
            code: message.code
        };

        response.json(data);

        return response.end();
    };

    // --------------------------------------------------------------------

    response.respondDeleted = (message?: RespondMessage) => {
        const defaultMessage = {
            statusCode: 200,
            message: 'Deleted',
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respond(message);
    };

    response.respondCreated = (message?: RespondMessage) => {
        const defaultMessage = {
            statusCode: 201,
            message: 'Created',
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respond(message);
    };

    response.respondAccepted = (message?: RespondMessage) => {
        const defaultMessage = {
            statusCode: 202,
            message: 'Accepted',
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respond(message);
    };

    // --------------------------------------------------------------------

    response.fail = (message?: RespondErrorMessage) => {
        if(message) {
            message.statusCode = message.statusCode ? message.statusCode : 400;
        }

        return response.respondException(message);
    };

    response.failUnauthorized = (message?: RespondErrorMessage) => {
        const defaultMessage = {
            statusCode: 401,
            message: 'Unauthorized',
            code: 'unauthorized'
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respondException(message);
    };

    response.failForbidden = (message?: RespondErrorMessage) => {
        const defaultMessage = {
            statusCode: 403,
            message: 'Forbidden',
            code: 'forbidden'
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respondException(message);
    };

    response.failNotFound = (message?: RespondErrorMessage) => {
        const defaultMessage = {
            statusCode: 404,
            message: 'Not Found',
            code: 'not-found'
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respondException(message);
    };

    response.failBadRequest = (message?: RespondErrorMessage) => {
        const defaultMessage = {
            statusCode: 400,
            message: 'Bad Request',
            code: 'bad-request'
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respondException(message);
    };

    response.failValidationError = (message?: RespondErrorMessage) => {
        const defaultMessage = {
            statusCode: 400,
            message: 'Bad Request',
            code: 'bad-request'
        }

        message = message || {};
        message = Object.assign(defaultMessage, message);

        return response.respondException(message);
    };

    response.failServerError = (message?: RespondErrorMessage) => {
        if(message) {
            message.statusCode = 500;
            message.message = message.message ? message.message : 'Internal Server Error';
            message.code = message.code ? message.code : 'server-error';
        }

        return response.respondException(message);
    };

    next();
}
