import { getRedisClient, isRedisAvailable } from '../db/redis.js';
import { getQueue } from '../queue/index.js';
import { getPrismaClient } from '../db/prisma.js';
import { Shield } from '@4runr/shield';
import { getShieldMisconfigurationWarnings } from '../security/shield-config.js';
import { env, createLogger } from '@4runr/shared';
const logger = createLogger('Gateway:Health');
function databaseUrlConfigured() {
    return Boolean(env.DATABASE_URL || process.env['DATABASE_URL']);
}
function redisUrlConfigured() {
    return Boolean(env.REDIS_URL || process.env['REDIS_URL']);
}
function rejectionMessage(reason, fallback) {
    if (reason instanceof Error)
        return reason.message;
    if (typeof reason === 'string')
        return reason;
    if (reason === undefined || reason === null)
        return fallback;
    return String(reason);
}
export async function checkDatabase() {
    const startTime = Date.now();
    if (!databaseUrlConfigured()) {
        return {
            status: 'up',
            responseTime: Date.now() - startTime,
            message: 'DATABASE_URL not set — no Postgres configured for this process (skipping DB probe)',
        };
    }
    try {
        const prisma = await getPrismaClient();
        await prisma.$queryRaw `SELECT 1`;
        const responseTime = Date.now() - startTime;
        return {
            status: 'up',
            responseTime,
            message: 'Postgres reachable (SELECT 1)',
        };
    }
    catch (error) {
        const responseTime = Date.now() - startTime;
        logger.warn('Database health check failed', {
            error: error instanceof Error ? error.message : String(error),
        });
        return {
            status: 'down',
            responseTime,
            error: error instanceof Error ? error.message : String(error),
            message: 'Postgres not reachable or Prisma client failed',
        };
    }
}
export async function checkRedis() {
    const startTime = Date.now();
    try {
        if (!redisUrlConfigured()) {
            return {
                status: 'up',
                responseTime: Date.now() - startTime,
                message: 'REDIS_URL not set — Redis not required for readiness',
            };
        }
        const available = await isRedisAvailable();
        if (!available) {
            return {
                status: 'down',
                responseTime: Date.now() - startTime,
                message: 'REDIS_URL set but Redis is unreachable (start redis-server or Docker, then retry)',
            };
        }
        const redis = await getRedisClient();
        if (!redis) {
            return {
                status: 'down',
                responseTime: Date.now() - startTime,
                message: 'Redis client not available',
            };
        }
        const result = await redis.ping();
        const responseTime = Date.now() - startTime;
        if (result === 'PONG') {
            return {
                status: 'up',
                responseTime,
                message: 'Redis connection healthy',
            };
        }
        return {
            status: 'degraded',
            responseTime,
            message: 'Redis ping returned unexpected result',
        };
    }
    catch (error) {
        const responseTime = Date.now() - startTime;
        logger.warn('Redis health check failed', {
            error: error instanceof Error ? error.message : String(error),
        });
        return {
            status: 'down',
            responseTime,
            error: error instanceof Error ? error.message : String(error),
            message: 'Redis connection failed',
        };
    }
}
export async function checkQueue() {
    const startTime = Date.now();
    try {
        const queue = getQueue();
        if (!queue) {
            if (!redisUrlConfigured()) {
                return {
                    status: 'up',
                    responseTime: Date.now() - startTime,
                    message: 'No run queue (Redis not configured)',
                };
            }
            return {
                status: 'down',
                responseTime: Date.now() - startTime,
                message: 'Run queue not initialized — Redis configured but BullMQ queue unavailable',
            };
        }
        const queueName = queue.name ?? 'unknown';
        const responseTime = Date.now() - startTime;
        return {
            status: 'up',
            responseTime,
            message: `Run queue ready (${queueName})`,
        };
    }
    catch (error) {
        const responseTime = Date.now() - startTime;
        logger.warn('Queue health check failed', {
            error: error instanceof Error ? error.message : String(error),
        });
        return {
            status: 'down',
            responseTime,
            error: error instanceof Error ? error.message : String(error),
            message: 'Queue system check failed',
        };
    }
}
export async function checkShield() {
    try {
        const shield = Shield.getInstance();
        const health = shield.getHealth();
        const config = shield.getConfig();
        const openAiApiKey = process.env['OPENAI_API_KEY'];
        const warnings = getShieldMisconfigurationWarnings(config, openAiApiKey);
        const status = warnings.length > 0 ? 'misconfigured' : 'operational';
        return {
            enabled: shield.isEnabled(),
            mode: health.mode,
            detectors: health.detectors,
            status,
            ...(warnings.length > 0 && { warnings }),
        };
    }
    catch (error) {
        logger.warn('Shield health check failed', {
            error: error instanceof Error ? error.message : String(error),
        });
        return {
            enabled: false,
            mode: 'unknown',
            detectors: {
                pii: false,
                injection: false,
                hallucination: false,
            },
            status: 'misconfigured',
            warnings: ['Shield health check threw error'],
        };
    }
}
export async function performHealthChecks() {
    const checks = {};
    const [databaseCheck, redisCheck, queueCheck, shieldCheck] = await Promise.allSettled([
        checkDatabase(),
        checkRedis(),
        checkQueue(),
        checkShield(),
    ]);
    if (databaseCheck.status === 'fulfilled') {
        checks.database = databaseCheck.value;
    }
    else {
        const msg = rejectionMessage(databaseCheck.reason, 'Database check failed');
        checks.database = {
            status: 'down',
            message: msg,
            error: msg,
        };
    }
    if (redisCheck.status === 'fulfilled') {
        checks.redis = redisCheck.value;
    }
    else {
        const msg = rejectionMessage(redisCheck.reason, 'Redis check failed');
        checks.redis = {
            status: 'down',
            message: msg,
            error: msg,
        };
    }
    if (queueCheck.status === 'fulfilled') {
        checks.queue = queueCheck.value;
    }
    else {
        const msg = rejectionMessage(queueCheck.reason, 'Queue check failed');
        checks.queue = {
            status: 'down',
            message: msg,
            error: msg,
        };
    }
    if (shieldCheck.status === 'fulfilled') {
        checks.shield = shieldCheck.value;
    }
    else {
        const msg = rejectionMessage(shieldCheck.reason, 'Shield check failed');
        checks.shield = {
            enabled: false,
            mode: 'unknown',
            detectors: { pii: false, injection: false, hallucination: false },
            status: 'misconfigured',
            warnings: [msg],
        };
    }
    const db = checks.database;
    const redis = checks.redis;
    const queue = checks.queue;
    const dbRequired = databaseUrlConfigured();
    const redisRequired = redisUrlConfigured();
    const databaseDown = dbRequired && db?.status === 'down';
    const redisDown = redisRequired && redis?.status === 'down';
    const queueDown = redisRequired && queue?.status === 'down';
    const hasDegraded = Object.values(checks).some((check) => check?.status === 'degraded');
    let status = 'healthy';
    if (databaseDown || redisDown) {
        status = 'unhealthy';
    }
    else if (queueDown || hasDegraded) {
        status = 'degraded';
    }
    return {
        status,
        checks,
        timestamp: new Date().toISOString(),
    };
}
export function computeReady(health) {
    const dbRequired = databaseUrlConfigured();
    const redisRequired = redisUrlConfigured();
    if (dbRequired && health.checks.database?.status !== 'up') {
        return false;
    }
    if (redisRequired && health.checks.redis?.status !== 'up') {
        return false;
    }
    return true;
}
export async function isReady() {
    const health = await performHealthChecks();
    return computeReady(health);
}
export function isAlive() {
    return true;
}
//# sourceMappingURL=index.js.map