"use strict";
/**
 * Shared storage for call data
 * This module provides Redis-based storage for call data with in-memory fallback
 * that can be accessed by both phone-util.ts and webhook controllers
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.storeCallData = storeCallData;
exports.getCallData = getCallData;
exports.updateCallData = updateCallData;
exports.deleteCallData = deleteCallData;
exports.getAllCallSids = getAllCallSids;
exports.extendCallDataTTL = extendCallDataTTL;
exports.hasCallData = hasCallData;
const logger_1 = __importDefault(require("../../logger"));
const redisClient_1 = require("../../util/redisClient");
const REDIS_PREFIX = 'call_data:';
const DEFAULT_TTL = 60 * 60 * 2; // 2 hours in seconds (calls typically don't last longer)
// In-memory fallback storage when Redis is unavailable
const inMemoryCallData = new Map();
// Track if we've warned about fallback
let hasWarnedAboutFallback = false;
const warnAboutFallback = () => {
    if (!hasWarnedAboutFallback) {
        logger_1.default.debug('Using in-memory call data storage (Redis unavailable)');
        hasWarnedAboutFallback = true;
    }
};
/**
 * Store call data for a given call SID
 */
async function storeCallData(callSid, data) {
    const callData = {
        ...data,
        currentStepIndex: 0,
    };
    try {
        if (!(0, redisClient_1.isRedisAvailable)()) {
            // Fallback to in-memory storage
            warnAboutFallback();
            inMemoryCallData.set(callSid, callData);
            logger_1.default.debug(`Stored call data ${callSid} in memory (Redis unavailable)`);
            return;
        }
        const redis = (0, redisClient_1.getRedisClient)();
        const key = `${REDIS_PREFIX}${callSid}`;
        await redis.setex(key, DEFAULT_TTL, JSON.stringify(callData));
        logger_1.default.debug(`Stored call data ${callSid} in Redis`);
    }
    catch (error) {
        logger_1.default.warn(`Failed to store call data ${callSid} in Redis, falling back to memory: ${error}`);
        warnAboutFallback();
        // Fallback to in-memory storage on error
        inMemoryCallData.set(callSid, callData);
    }
}
/**
 * Get call data for a given call SID
 */
async function getCallData(callSid) {
    try {
        if (!(0, redisClient_1.isRedisAvailable)()) {
            // Fallback to in-memory storage
            return inMemoryCallData.get(callSid);
        }
        const redis = (0, redisClient_1.getRedisClient)();
        const key = `${REDIS_PREFIX}${callSid}`;
        const data = await redis.get(key);
        if (!data) {
            // Check in-memory fallback if not found in Redis
            return inMemoryCallData.get(callSid);
        }
        return JSON.parse(data);
    }
    catch (error) {
        logger_1.default.warn(`Failed to get call data ${callSid} from Redis, checking memory: ${error}`);
        // Fallback to in-memory storage on error
        return inMemoryCallData.get(callSid);
    }
}
/**
 * Update call data (e.g., increment step index)
 */
async function updateCallData(callSid, updates) {
    try {
        if (!(0, redisClient_1.isRedisAvailable)()) {
            // Fallback to in-memory storage
            const existing = inMemoryCallData.get(callSid);
            if (existing) {
                inMemoryCallData.set(callSid, { ...existing, ...updates });
            }
            return;
        }
        const redis = (0, redisClient_1.getRedisClient)();
        const key = `${REDIS_PREFIX}${callSid}`;
        // Get existing call data
        const existingData = await redis.get(key);
        if (!existingData) {
            // Check in-memory fallback
            const existing = inMemoryCallData.get(callSid);
            if (existing) {
                inMemoryCallData.set(callSid, { ...existing, ...updates });
            }
            return;
        }
        const existingCallData = JSON.parse(existingData);
        const updatedCallData = { ...existingCallData, ...updates };
        // Get remaining TTL
        const ttl = await redis.ttl(key);
        const newTtl = ttl > 0 ? ttl : DEFAULT_TTL;
        await redis.setex(key, newTtl, JSON.stringify(updatedCallData));
    }
    catch (error) {
        logger_1.default.warn(`Failed to update call data ${callSid} in Redis, trying memory: ${error}`);
        // Fallback to in-memory storage on error
        const existing = inMemoryCallData.get(callSid);
        if (existing) {
            inMemoryCallData.set(callSid, { ...existing, ...updates });
        }
    }
}
/**
 * Delete call data
 */
async function deleteCallData(callSid) {
    try {
        if (!(0, redisClient_1.isRedisAvailable)()) {
            // Fallback to in-memory storage
            inMemoryCallData.delete(callSid);
            return;
        }
        const redis = (0, redisClient_1.getRedisClient)();
        const key = `${REDIS_PREFIX}${callSid}`;
        await redis.del(key);
        // Also remove from in-memory fallback if it exists
        inMemoryCallData.delete(callSid);
    }
    catch (error) {
        logger_1.default.warn(`Failed to delete call data ${callSid} from Redis, trying memory: ${error}`);
        // Fallback to in-memory storage on error
        inMemoryCallData.delete(callSid);
    }
}
/**
 * Get all call SIDs currently stored
 */
async function getAllCallSids() {
    try {
        if (!(0, redisClient_1.isRedisAvailable)()) {
            // Fallback to in-memory storage
            return Array.from(inMemoryCallData.keys());
        }
        const redis = (0, redisClient_1.getRedisClient)();
        const keys = await redis.keys(`${REDIS_PREFIX}*`);
        const callSids = keys.map((key) => key.replace(REDIS_PREFIX, ''));
        // Merge with in-memory fallback
        const memorySids = Array.from(inMemoryCallData.keys());
        const allSids = new Set([...callSids, ...memorySids]);
        return Array.from(allSids);
    }
    catch (error) {
        logger_1.default.warn(`Failed to get all call SIDs from Redis, using memory: ${error}`);
        // Fallback to in-memory storage on error
        return Array.from(inMemoryCallData.keys());
    }
}
/**
 * Extend TTL for call data (no-op for in-memory fallback)
 */
async function extendCallDataTTL(callSid, additionalSeconds = 3600) {
    try {
        if (!(0, redisClient_1.isRedisAvailable)()) {
            // No-op for in-memory storage (no TTL)
            return;
        }
        const redis = (0, redisClient_1.getRedisClient)();
        const key = `${REDIS_PREFIX}${callSid}`;
        await redis.expire(key, additionalSeconds);
    }
    catch (error) {
        logger_1.default.warn(`Failed to extend TTL for call data ${callSid} in Redis: ${error}`);
        // No-op on error (in-memory has no TTL)
    }
}
/**
 * Check if call data exists
 */
async function hasCallData(callSid) {
    try {
        if (!(0, redisClient_1.isRedisAvailable)()) {
            // Fallback to in-memory storage
            return inMemoryCallData.has(callSid);
        }
        const redis = (0, redisClient_1.getRedisClient)();
        const key = `${REDIS_PREFIX}${callSid}`;
        const exists = await redis.exists(key);
        return exists === 1 || inMemoryCallData.has(callSid);
    }
    catch (error) {
        logger_1.default.warn(`Failed to check if call data ${callSid} exists in Redis, checking memory: ${error}`);
        // Fallback to in-memory storage on error
        return inMemoryCallData.has(callSid);
    }
}
//# sourceMappingURL=call-data-storage.js.map