/**
 * Shared Health Route Handlers
 * Extracted to eliminate duplication between CoreRoutes.ts and routes/health.ts
 */
import { appConfig } from '../config/app.js';
import { RuntimeHealthProbes } from '../health/RuntimeHealthProbes.js';
import { HealthUtils } from './ExternalServiceUtils.js';
import { databaseConfig } from '../config/database.js';
import { Env } from '../config/env.js';
import { Logger } from '../config/logger.js';
import { Router } from '../routes/Router.js';
import { useDatabase } from '../orm/Database.js';
import { QueryBuilder } from '../orm/QueryBuilder.js';
const isMissingDefaultDatabase = (error) => {
    if (typeof error !== 'object' || error === null)
        return false;
    const maybe = error;
    if (maybe.name !== 'ConfigError' || maybe.code !== 'CONFIG_ERROR')
        return false;
    return typeof maybe.message === 'string'
        ? maybe.message.includes("Database connection 'default' is not registered")
        : false;
};
const ensureDefaultDatabase = async () => {
    try {
        return useDatabase();
    }
    catch (error) {
        if (!isMissingDefaultDatabase(error))
            throw error;
        try {
            const mod = await import('../orm/DatabaseRuntimeRegistration.js');
            mod.registerDatabasesFromRuntimeConfig?.(databaseConfig);
            return useDatabase();
        }
        catch (innerError) {
            Logger.warn('Database registration failed; skipping health DB check', innerError);
            return null;
        }
    }
};
/**
 * Health check endpoint handler
 */
async function handleHealthRoute(_req, res) {
    const environment = Env.NODE_ENV ?? 'development';
    try {
        const db = await ensureDefaultDatabase();
        if (db === null) {
            const uptime = HealthUtils.getUptime();
            res.json(HealthUtils.buildHealthResponse('healthy', environment, {
                uptime,
                database: 'unconfigured',
            }));
            return;
        }
        const maybeIsConnected = db.isConnected;
        const maybeConnect = db.connect;
        if (typeof maybeIsConnected === 'function' && maybeIsConnected.call(db) === false) {
            if (typeof maybeConnect === 'function') {
                await maybeConnect.call(db);
            }
        }
        await QueryBuilder.ping(db);
        const uptime = HealthUtils.getUptime();
        res.json(HealthUtils.buildHealthResponse('healthy', environment, {
            uptime,
            database: 'connected',
        }));
    }
    catch (error) {
        Logger.error('Health check failed:', error);
        res.setStatus(503).json(HealthUtils.buildErrorResponse('unhealthy', environment, error, {
            database: 'disconnected',
        }));
    }
}
/**
 * Liveness probe endpoint handler
 */
function handleHealthLiveRoute(_req, res) {
    const uptime = HealthUtils.getUptime();
    res.json(HealthUtils.buildHealthResponse('alive', Env.NODE_ENV ?? 'development', {
        uptime,
    }));
}
/**
 * Readiness probe endpoint handler
 */
async function handleHealthReadyRoute(_req, res) {
    const startTime = Date.now();
    const environment = appConfig.environment;
    let databaseResponseTime = null;
    let cacheResponseTime = null;
    try {
        const db = await ensureDefaultDatabase();
        if (db === null) {
            res.json(HealthUtils.buildHealthResponse('ready', environment, {
                dependencies: {
                    database: {
                        status: 'unconfigured',
                        responseTime: 0,
                    },
                },
            }));
            return;
        }
        const maybeIsConnected = db.isConnected;
        const maybeConnect = db.connect;
        if (typeof maybeIsConnected === 'function' && maybeIsConnected.call(db) === false) {
            if (typeof maybeConnect === 'function') {
                await maybeConnect.call(db);
            }
        }
        await QueryBuilder.ping(db);
        databaseResponseTime = Date.now() - startTime;
        cacheResponseTime = await RuntimeHealthProbes.pingKvCache(2000);
        res.json(HealthUtils.buildHealthResponse('ready', environment, {
            dependencies: {
                database: {
                    status: 'ready',
                    responseTime: databaseResponseTime,
                },
                ...(cacheResponseTime === null
                    ? {}
                    : {
                        cache: {
                            status: 'ready',
                            responseTime: cacheResponseTime,
                        },
                    }),
            },
        }));
    }
    catch (error) {
        Logger.error('Readiness check failed:', error);
        const responseTime = Date.now() - startTime;
        const dependencies = {
            database: {
                status: databaseResponseTime === null ? 'unavailable' : 'ready',
                responseTime: databaseResponseTime ?? responseTime,
            },
        };
        if (RuntimeHealthProbes.getCacheDriverName() === 'kv') {
            dependencies['cache'] = {
                status: 'unavailable',
                responseTime: cacheResponseTime ?? responseTime,
            };
        }
        res.setStatus(503).json(HealthUtils.buildErrorResponse('not_ready', environment, error, {
            dependencies,
        }));
    }
}
/**
 * Register all health routes
 */
export const registerHealthRoutes = (router) => {
    Router.get(router, '/health', handleHealthRoute);
    Router.get(router, '/health/live', handleHealthLiveRoute);
    Router.get(router, '/health/ready', handleHealthReadyRoute);
};
