"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const child_process_1 = require("child_process");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const pm2_1 = __importDefault(require("pm2"));
const pm2_connection_1 = require("../utils/pm2-connection");
const router = (0, express_1.Router)();
// @group Utilities : Resolve pm2 binary path via shell
const runPM2CLI = (args) => new Promise((resolve, reject) => {
    var _a, _b;
    // Use shell so the OS resolves the global pm2 binary from PATH
    const child = (0, child_process_1.exec)(`pm2 ${args}`);
    let out = '';
    let err = '';
    (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (d) => { out += d.toString(); });
    (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (d) => { err += d.toString(); });
    child.on('close', (code) => {
        if (code !== 0) {
            reject(new Error(err || `pm2 exited with code ${code}`));
        }
        else {
            resolve({ stdout: out, stderr: err });
        }
    });
    child.on('error', (e) => reject(e));
});
// @group APIEndpoints : List installed PM2 modules
router.get('/', async (_req, res) => {
    try {
        // Use PM2 Node.js API — modules appear as regular processes with module metadata
        const processList = await (0, pm2_connection_1.executePM2Command)((cb) => pm2_1.default.list(cb));
        // PM2 modules have pm2_env.pmx_module === true
        const modules = processList
            .filter((proc) => { var _a; return ((_a = proc.pm2_env) === null || _a === void 0 ? void 0 : _a.pmx_module) === true; })
            .map((proc) => {
            var _a, _b, _c;
            return ({
                name: proc.name,
                version: ((_a = proc.pm2_env) === null || _a === void 0 ? void 0 : _a.version) || ((_b = proc.pm2_env) === null || _b === void 0 ? void 0 : _b.MODULE_VERSION) || 'N/A',
                status: ((_c = proc.pm2_env) === null || _c === void 0 ? void 0 : _c.status) || 'unknown',
                pid: proc.pid,
                pm_id: proc.pm_id,
            });
        });
        res.json(modules);
    }
    catch (error) {
        // Fallback: parse pm2 module:list CLI output
        try {
            const { stdout } = await runPM2CLI('module:list');
            const moduleLines = stdout
                .split('\n')
                .filter(line => line.includes('│') && !line.includes('Module') && line.trim() !== '');
            const modules = moduleLines
                .map(line => {
                const parts = line.split('│').map(part => part.trim()).filter(Boolean);
                if (parts.length >= 3) {
                    return { name: parts[0], version: parts[1], status: parts[2] };
                }
                return null;
            })
                .filter(Boolean);
            res.json(modules);
        }
        catch (fallbackError) {
            res.status(500).json({
                error: 'Failed to list PM2 modules',
                details: fallbackError.message
            });
        }
    }
});
// @group APIEndpoints : Install a PM2 module
router.post('/install', async (req, res) => {
    const { moduleName } = req.body;
    if (!moduleName) {
        return res.status(400).json({ error: 'Module name is required' });
    }
    // Basic validation — only allow alphanumeric, @, /, -, .
    if (!/^[@a-zA-Z0-9/_\-.]+$/.test(moduleName)) {
        return res.status(400).json({ error: 'Invalid module name' });
    }
    try {
        const { stdout } = await runPM2CLI(`install ${moduleName}`);
        res.json({
            success: true,
            message: `Successfully installed module: ${moduleName}`,
            details: stdout
        });
    }
    catch (error) {
        res.status(500).json({
            error: `Failed to install module: ${moduleName}`,
            details: error.message
        });
    }
});
// @group APIEndpoints : Uninstall a PM2 module
router.delete('/:moduleName', async (req, res) => {
    const { moduleName } = req.params;
    if (!moduleName) {
        return res.status(400).json({ error: 'Module name is required' });
    }
    // Basic validation
    if (!/^[@a-zA-Z0-9/_\-.]+$/.test(moduleName)) {
        return res.status(400).json({ error: 'Invalid module name' });
    }
    try {
        const { stdout } = await runPM2CLI(`uninstall ${moduleName}`);
        res.json({
            success: true,
            message: `Successfully uninstalled module: ${moduleName}`,
            details: stdout
        });
    }
    catch (error) {
        res.status(500).json({
            error: `Failed to uninstall module: ${moduleName}`,
            details: error.message
        });
    }
});
// @group Utilities : Resolve ~/.pm2/module_conf.json path
const moduleConfPath = () => path_1.default.join(os_1.default.homedir(), '.pm2', 'module_conf.json');
// @group APIEndpoints : Get config for a specific installed module
router.get('/:moduleName/config', (req, res) => {
    var _a;
    const { moduleName } = req.params;
    if (!/^[@a-zA-Z0-9/_\-.]+$/.test(moduleName)) {
        return res.status(400).json({ error: 'Invalid module name' });
    }
    const confFile = moduleConfPath();
    if (!fs_1.default.existsSync(confFile)) {
        return res.json({ config: {} });
    }
    try {
        const raw = JSON.parse(fs_1.default.readFileSync(confFile, 'utf8'));
        // PM2 stores module config under the module name key
        const config = (_a = raw[moduleName]) !== null && _a !== void 0 ? _a : {};
        res.json({ config });
    }
    catch {
        res.status(500).json({ error: 'Failed to read module configuration' });
    }
});
// @group APIEndpoints : Set one or more config keys for an installed module
router.put('/:moduleName/config', async (req, res) => {
    const { moduleName } = req.params;
    const { config } = req.body;
    if (!/^[@a-zA-Z0-9/_\-.]+$/.test(moduleName)) {
        return res.status(400).json({ error: 'Invalid module name' });
    }
    if (!config || typeof config !== 'object') {
        return res.status(400).json({ error: 'config object is required' });
    }
    // Validate all keys — no shell metacharacters
    for (const key of Object.keys(config)) {
        if (!/^[a-zA-Z0-9_\-.]+$/.test(key)) {
            return res.status(400).json({ error: `Invalid config key: ${key}` });
        }
    }
    try {
        // Run pm2 set for each key sequentially
        for (const [key, value] of Object.entries(config)) {
            // Wrap value in quotes to handle spaces; strip any embedded quotes first
            const safeValue = String(value).replace(/"/g, '');
            await runPM2CLI(`set ${moduleName}:${key} "${safeValue}"`);
        }
        res.json({ success: true, message: `Configuration updated for ${moduleName}` });
    }
    catch (error) {
        res.status(500).json({ error: 'Failed to update configuration', details: error.message });
    }
});
exports.default = router;
