"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.executePM2Command = exports.disconnectFromPM2 = exports.connectToPM2 = void 0;
const pm2_1 = __importDefault(require("pm2"));
/**
 * Utility to manage PM2 connections
 * This implements connection pooling to avoid the overhead of
 * repeatedly connecting and disconnecting to PM2
 */
let isConnected = false;
let connectionPromise = null;
let connectionRetries = 0;
const MAX_RETRIES = 3;
const RETRY_DELAY = 1000;
/**
 * Check if PM2 is installed and available
 */
const checkPM2Installation = () => {
    return new Promise((resolve) => {
        const { exec } = require('child_process');
        exec('pm2 --version', (error) => {
            if (error) {
                console.error('PM2 is not installed or not available in PATH');
                resolve(false);
            }
            else {
                resolve(true);
            }
        });
    });
};
/**
 * Connect to PM2 if not already connected
 * Returns a promise that resolves when the connection is established
 */
const connectToPM2 = async () => {
    // If already connected, return resolved promise
    if (isConnected) {
        return Promise.resolve();
    }
    // If a connection attempt is in progress, return that promise
    if (connectionPromise) {
        return connectionPromise;
    }
    // First check if PM2 is installed
    const isPM2Installed = await checkPM2Installation();
    if (!isPM2Installed) {
        return Promise.reject(new Error('PM2 is not installed or not in your PATH. Please install PM2 globally using: npm install -g pm2'));
    }
    // Start a new connection attempt
    connectionPromise = new Promise((resolve, reject) => {
        pm2_1.default.connect((err) => {
            if (err) {
                console.error('Failed to connect to PM2:', err);
                // Retry logic
                if (connectionRetries < MAX_RETRIES) {
                    connectionRetries++;
                    connectionPromise = null;
                    // Wait and try again
                    setTimeout(() => {
                        (0, exports.connectToPM2)()
                            .then(resolve)
                            .catch(reject);
                    }, RETRY_DELAY);
                }
                else {
                    // Max retries reached
                    connectionRetries = 0;
                    connectionPromise = null;
                    reject(err);
                }
            }
            else {
                isConnected = true;
                connectionRetries = 0;
                resolve();
            }
        });
    });
    return connectionPromise;
};
exports.connectToPM2 = connectToPM2;
/**
 * Safely disconnect from PM2
 * Use this when shutting down the server
 */
const disconnectFromPM2 = () => {
    return new Promise((resolve) => {
        if (isConnected) {
            pm2_1.default.disconnect();
            isConnected = false;
            connectionPromise = null;
        }
        resolve();
    });
};
exports.disconnectFromPM2 = disconnectFromPM2;
/**
 * Execute a PM2 command with automatic connection handling
 * This will connect to PM2 if needed, run the command,
 * and properly handle the result
 */
// @group ConnectionPool : Execute a PM2 command using the shared pooled connection
const executePM2Command = async (command) => {
    try {
        await (0, exports.connectToPM2)();
        return new Promise((resolve, reject) => {
            command((err, result) => {
                if (err) {
                    reject(err);
                }
                else {
                    resolve(result);
                }
            });
        });
    }
    catch (err) {
        // If connection fails, ensure we reset the connection state
        isConnected = false;
        connectionPromise = null;
        throw err;
    }
};
exports.executePM2Command = executePM2Command;
// Handle process termination to clean up PM2 connection
process.on('SIGINT', () => {
    (0, exports.disconnectFromPM2)().then(() => {
        process.exit(0);
    });
});
process.on('SIGTERM', () => {
    (0, exports.disconnectFromPM2)().then(() => {
        process.exit(0);
    });
});
