/**
 * Error Routing
 * Centralizes 404/500 handling and HTML error page rendering.
 */
import { appConfig } from '../config/app.js';
import { HTTP_HEADERS, MIME_TYPES } from '../config/constants.js';
import { serveErrorPagesFileAsync, serveZintrustSvgFile, serveZintrustSvgFileAsync, } from './errorPages.js';
import { getPublicRoot } from './publicRoot.js';
import { Router } from './Router.js';
import { ErrorFactory } from '../exceptions/ZintrustError.js';
import { ErrorPageRenderer } from '../http/error-pages/ErrorPageRenderer.js';
import { ErrorResponse } from '../http/ErrorResponse.js';
// Cache Set at module level to avoid repeated creation
const REDACTED_HEADERS = new Set(['authorization', 'cookie', 'set-cookie', 'x-api-key']);
const redactHeaders = (headers) => {
    const out = {};
    for (const [key, value] of Object.entries(headers)) {
        if (REDACTED_HEADERS.has(key.toLowerCase())) {
            out[key] = '[redacted]';
            continue;
        }
        out[key] = value;
    }
    return out;
};
const safeJsonStringify = (value) => {
    try {
        return JSON.stringify(value, null, 2) ?? '';
    }
    catch {
        return '';
    }
};
const trySendHtmlErrorPage = async (request, response, input) => {
    if (!ErrorPageRenderer.shouldSendHtml(request))
        return false;
    const publicRoot = getPublicRoot();
    const html = await ErrorPageRenderer.renderHtmlAsync(publicRoot, {
        statusCode: input.statusCode,
        errorName: input.errorName,
        errorMessage: input.errorMessage,
        requestPath: request.getPath(),
        stackPretty: input.stackPretty,
        stackRaw: input.stackRaw,
        requestPretty: input.requestPretty,
        requestRaw: input.requestRaw,
    });
    if (html === undefined)
        return false;
    response.html(html);
    return true;
};
const handleNotFound = async (request, response, requestId) => {
    const path = request.getPath();
    if (path.startsWith('/error-pages/')) {
        await serveErrorPagesFileAsync(path, response);
        return;
    }
    if (path === '/zintrust.svg') {
        if (!(await serveZintrustSvgFileAsync(response))) {
            serveZintrustSvgFile(response);
        }
        return;
    }
    response.setStatus(404);
    if (await trySendHtmlErrorPage(request, response, {
        statusCode: 404,
        errorName: 'Not Found',
        errorMessage: 'The page you requested could not be found.',
    })) {
        return;
    }
    response.json(ErrorResponse.notFound('Route', requestId));
};
const handleInternalServerErrorWithWrappers = async (request, response, error, requestId) => {
    response.setStatus(500);
    const isDev = appConfig.isDevelopment();
    const err = error instanceof Error ? error : ErrorFactory.createGeneralError('Unknown error', error);
    const errorName = isDev ? err.name || 'Error' : 'Internal Server Error';
    const errorMessage = isDev
        ? err.message || 'An error has occurred'
        : 'Something went wrong while handling your request.';
    const requestObj = isDev
        ? {
            method: request.getMethod(),
            path: request.getPath(),
            query: request.getQuery(),
            headers: redactHeaders(request.getHeaders()),
        }
        : undefined;
    const requestPretty = requestObj === undefined
        ? undefined
        : `Request\n\nMethod: ${requestObj.method}\nPath: ${requestObj.path}\n\nHeaders:\n${safeJsonStringify(requestObj.headers)}\n\nQuery:\n${safeJsonStringify(requestObj.query)}`;
    const requestRaw = requestObj === undefined ? undefined : safeJsonStringify(requestObj);
    const stackPretty = isDev ? err.stack ?? '' : undefined;
    const stackRaw = isDev
        ? safeJsonStringify({ name: err.name, message: err.message, stack: err.stack })
        : undefined;
    if (await trySendHtmlErrorPage(request, response, {
        statusCode: 500,
        errorName,
        errorMessage,
        stackPretty,
        stackRaw,
        requestPretty,
        requestRaw,
    })) {
        return;
    }
    response.json(ErrorResponse.internalServerError('Internal server error', requestId, isDev ? err.stack : undefined));
};
const handleInternalServerErrorRaw = (res) => {
    res.writeHead(500, { [HTTP_HEADERS.CONTENT_TYPE]: MIME_TYPES.JSON });
    res.end(JSON.stringify(ErrorResponse.internalServerError('Internal server error')));
};
const handleForced404 = async (req, res) => {
    await handleNotFound(req, res);
};
const handleForced500 = async (req, res) => {
    const forced = ErrorFactory.createGeneralError('Forced 500 route', {
        route: '/500',
    });
    await handleInternalServerErrorWithWrappers(req, res, forced);
};
/**
 * Debug routes to always render 404/500 responses.
 */
export const registerErrorRoutes = (router) => {
    Router.get(router, '/404', handleForced404);
    Router.get(router, '/500', handleForced500);
};
export const ErrorRouting = Object.freeze({
    getPublicRoot,
    registerErrorRoutes,
    handleNotFound,
    handleInternalServerErrorWithWrappers,
    handleInternalServerErrorRaw,
});
export default ErrorRouting;
