"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.closeRedisClient = exports.isRedisAvailable = exports.getRedisClient = exports.initializeRedisClient = void 0;
const ioredis_1 = __importDefault(require("ioredis"));
const logger_1 = __importDefault(require("../logger"));
let redisClient = null;
let redisConnectionFailed = false;
let isInitialized = false;
/**
 * Initialize Redis connection on server startup
 * This should be called once in server.ts
 */
const initializeRedisClient = async () => {
    if (isInitialized) {
        logger_1.default.debug('Redis client already initialized');
        return;
    }
    const redisHost = process.env.REDIS_HOST || 'trusys-redis-dtxoic.serverless.aps1.cache.amazonaws.com';
    const redisPort = Number(process.env.REDIS_PORT) || 6379;
    const redisPassword = process.env.REDIS_PASSWORD;
    // Suppress unhandled rejection warnings during Redis initialization
    const suppressUnhandledRejection = () => {
        // Silently ignore unhandled rejections during Redis init
    };
    process.on('unhandledRejection', suppressUnhandledRejection);
    try {
        logger_1.default.info('Initializing Redis client...');
        // Determine if we should use TLS (only for AWS, not localhost)
        const shouldUseTLS = redisHost !== 'localhost' && redisHost !== '127.0.0.1';
        const redisConfig = {
            host: redisHost,
            port: redisPort,
            ...(shouldUseTLS && {
                tls: {
                    // Enable TLS for AWS ElastiCache
                    rejectUnauthorized: false,
                },
            }),
            retryStrategy: (times) => {
                if (times > 3) {
                    // Stop retrying after 3 attempts and mark as failed
                    redisConnectionFailed = true;
                    return null; // Stop retrying
                }
                const delay = Math.min(times * 1000, 3000);
                return delay;
            },
            maxRetriesPerRequest: 3,
            enableOfflineQueue: true, // Queue commands until connected
            connectTimeout: 5000, // 5 second timeout for initial connection
            lazyConnect: true, // Don't auto-connect, we'll do it explicitly
        };
        // Only add password if it exists
        if (redisPassword) {
            redisConfig.password = redisPassword;
        }
        redisClient = new ioredis_1.default(redisConfig);
        // Suppress error logs during initial connection attempt
        let isInitialConnection = true;
        // Handle connection events
        redisClient.on('connect', () => {
            logger_1.default.info('✅ Redis client connected successfully');
            redisConnectionFailed = false;
            isInitialConnection = false;
        });
        redisClient.on('ready', () => {
            logger_1.default.info('✅ Redis client ready');
            redisConnectionFailed = false;
            isInitialConnection = false;
        });
        redisClient.on('error', (err) => {
            // Suppress errors during initial connection (we handle them in try/catch)
            if (isInitialConnection) {
                redisConnectionFailed = true;
                return;
            }
            // Log errors after initial connection
            if (err.message.includes('ETIMEDOUT') || err.message.includes('ECONNREFUSED')) {
                redisConnectionFailed = true;
                logger_1.default.warn(`⚠️  Redis connection lost: ${err.message}`);
            }
            else {
                logger_1.default.error(`Redis client error: ${err.message}`);
            }
        });
        redisClient.on('close', () => {
            if (!isInitialConnection) {
                logger_1.default.warn('Redis client connection closed');
            }
        });
        redisClient.on('reconnecting', () => {
            logger_1.default.info('Redis client reconnecting...');
            isInitialConnection = false;
        });
        // Try to connect with timeout
        try {
            await Promise.race([
                redisClient.connect().catch((err) => {
                    // Catch and re-throw to prevent unhandled rejection
                    throw err;
                }),
                new Promise((_, reject) => setTimeout(() => reject(new Error('TIMEOUT')), 5000)),
            ]);
            logger_1.default.info('✅ Redis connection established');
            isInitialConnection = false;
        }
        catch {
            redisConnectionFailed = true;
            isInitialConnection = false;
            // Clean error message without stack trace
            logger_1.default.warn('⚠️  Redis connection failed: Unable to connect to Redis server');
            logger_1.default.warn('⚠️  Using in-memory job storage. For multi-server deployments, ensure Redis is accessible.');
            // Close the failed connection attempt and suppress further errors
            if (redisClient) {
                redisClient.removeAllListeners();
                try {
                    redisClient.disconnect(false);
                }
                catch {
                    // Ignore disconnect errors
                }
            }
            // Don't throw - allow server to start with fallback
        }
        isInitialized = true;
    }
    catch {
        logger_1.default.warn('⚠️  Error initializing Redis client');
        logger_1.default.warn('⚠️  Using in-memory job storage');
        redisConnectionFailed = true;
        isInitialized = true;
        // Don't throw - allow server to start with fallback
    }
    finally {
        // Remove the unhandled rejection suppressor
        process.removeListener('unhandledRejection', suppressUnhandledRejection);
    }
};
exports.initializeRedisClient = initializeRedisClient;
/**
 * Get the Redis client instance (must call initializeRedisClient first)
 */
const getRedisClient = () => {
    if (!isInitialized) {
        throw new Error('Redis client not initialized. Call initializeRedisClient() first.');
    }
    if (redisConnectionFailed || !redisClient) {
        throw new Error('Redis unavailable, using in-memory fallback');
    }
    return redisClient;
};
exports.getRedisClient = getRedisClient;
/**
 * Check if Redis is available and connected
 */
const isRedisAvailable = () => {
    if (redisConnectionFailed) {
        return false;
    }
    if (!redisClient) {
        return false;
    }
    const status = redisClient.status;
    return status === 'ready' || status === 'connect' || status === 'connecting';
};
exports.isRedisAvailable = isRedisAvailable;
const closeRedisClient = async () => {
    if (redisClient) {
        await redisClient.quit();
        redisClient = null;
        logger_1.default.info('Redis client disconnected');
    }
};
exports.closeRedisClient = closeRedisClient;
// Graceful shutdown
process.on('SIGTERM', async () => {
    await (0, exports.closeRedisClient)();
    process.exit(0);
});
process.on('SIGINT', async () => {
    await (0, exports.closeRedisClient)();
    process.exit(0);
});
//# sourceMappingURL=redisClient.js.map