/*
 * Copyright (C) 2024-present Puter Technologies Inc.
 *
 * This file is part of Puter.
 *
 * Puter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
const APIError = require('./APIError');

/**
 * api_error_handler() is an express error handler for API errors.
 * It adheres to the express error handler signature and should be
 * used as the last middleware in an express app.
 *
 * Since Express 5 is not yet released, this function is used by
 * eggspress() to handle errors instead of as a middleware.
 *
 * @todo remove this function and use express error handling
 * when Express 5 is released
 *
 * @param {*} err
 * @param {*} req
 * @param {*} res
 * @param {*} next
 * @returns
 */
module.exports = function (err, req, res, next) {
    if ( res.headersSent ) {
        console.error('error after headers were sent:', err);
        return next(err);
    }

    // API errors might have a response to help the
    // developer resolve the issue.
    if ( err instanceof APIError ) {
        return err.write(res);
    }

    if (
        typeof err === 'object' &&
        !(err instanceof Error) &&
        err.hasOwnProperty('message')
    ) {
        const apiError = APIError.create(400, err);
        return apiError.write(res);
    }

    console.error('internal server error:', err);

    const services = globalThis.services;
    if ( services && services.has('alarm') ) {
        const alarm = services.get('alarm');
        alarm.create('api_error_handler', err.message, {
            error: err,
            url: req.url,
            method: req.method,
            body: req.body,
            headers: req.headers,
        });
    }

    req.__error_handled = true;

    // Other errors should provide as little information
    // to the client as possible for security reasons.
    return res.send(500, 'Internal Server Error');
};
