"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 pm2_1 = __importDefault(require("pm2"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const ProjectSetupService_1 = require("../services/ProjectSetupService");
const router = (0, express_1.Router)();
// Deploy a new application (SSE streaming)
router.post('/', async (req, res) => {
    const { name, script, cwd, namespace, instances, exec_mode, autorestart, watch, max_memory_restart, env, appType, autoSetup = true } = req.body;
    // Validate required fields before starting SSE
    if (!name || !script) {
        return res.status(400).json({ error: 'Name and script path are required' });
    }
    if (!fs_1.default.existsSync(script)) {
        return res.status(400).json({ error: `Script file not found: ${script}` });
    }
    // Switch to SSE
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.flushHeaders();
    const send = (type, data) => {
        if (!res.writableEnded) {
            res.write(`data: ${JSON.stringify({ type, ...data })}\n\n`);
        }
    };
    const log = (message) => send('log', { message });
    const done = (success, extra = {}) => {
        send('done', { success, ...extra });
        res.end();
    };
    try {
        const projectPath = cwd || path_1.default.dirname(script);
        let finalEnv = env || {};
        let interpreterPath = '';
        let setupResult = null;
        // Auto-detect project type
        let detectedType = appType;
        if (!detectedType) {
            detectedType = ProjectSetupService_1.projectSetupService.detectProjectType(projectPath);
            if (detectedType) {
                log(`Auto-detected project type: ${detectedType}`);
            }
        }
        // Run project setup
        if (autoSetup && detectedType && ['node', 'python', 'dotnet'].includes(detectedType)) {
            log(`Running ${detectedType} project setup...`);
            try {
                setupResult = await ProjectSetupService_1.projectSetupService.setupProject(projectPath, detectedType, log);
                if (!setupResult.success) {
                    return done(false, {
                        error: 'Project setup failed',
                        details: setupResult.errors,
                        warnings: setupResult.warnings
                    });
                }
                finalEnv = { ...setupResult.environment, ...finalEnv };
                if (setupResult.interpreterPath) {
                    interpreterPath = setupResult.interpreterPath;
                }
            }
            catch (setupError) {
                return done(false, {
                    error: 'Project setup failed',
                    details: setupError instanceof Error ? setupError.message : 'Unknown setup error'
                });
            }
        }
        // Build PM2 config
        const appConfig = {
            name,
            script,
            cwd: projectPath,
            namespace: namespace || 'default',
            instances: parseInt(instances) || 1,
            exec_mode: exec_mode || 'fork',
            autorestart: autorestart !== undefined ? autorestart : true,
            watch: watch || false,
            max_memory_restart: max_memory_restart || '150M',
            env: finalEnv
        };
        if (detectedType === 'python' && interpreterPath) {
            appConfig.interpreter = interpreterPath;
        }
        else if (detectedType === 'dotnet') {
            appConfig.interpreter = 'dotnet';
            const publishedDll = path_1.default.join(projectPath, 'publish', `${path_1.default.basename(projectPath)}.dll`);
            if (fs_1.default.existsSync(publishedDll)) {
                appConfig.script = publishedDll;
            }
        }
        log(`Starting PM2 process: ${name}`);
        await new Promise((resolve, reject) => {
            pm2_1.default.connect((err) => {
                if (err)
                    return reject(err);
                pm2_1.default.start(appConfig, (startErr) => {
                    pm2_1.default.disconnect();
                    if (startErr)
                        return reject(startErr);
                    resolve();
                });
            });
        });
        log(`Process "${name}" started successfully.`);
        done(true, {
            message: `Application ${name} deployed successfully`,
            setupResult: setupResult ? { steps: setupResult.steps, warnings: setupResult.warnings } : null
        });
    }
    catch (error) {
        console.error('Deployment error:', error);
        done(false, {
            error: 'Deployment failed',
            details: error instanceof Error ? error.message : 'Unknown error'
        });
    }
});
// Generate ecosystem.config.js file
router.post('/generate-ecosystem', (req, res) => {
    pm2_1.default.connect(async (err) => {
        if (err) {
            console.error(err);
            return res.status(500).json({ error: 'Failed to connect to PM2' });
        }
        try {
            // Get all processes
            const listPromise = new Promise((resolve, reject) => {
                pm2_1.default.list((err, processList) => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    resolve(processList);
                });
            });
            const processList = await listPromise;
            // Filter processes if needed
            let filteredProcesses = processList;
            if (req.body.includeAllProcesses === false) {
                filteredProcesses = processList.filter(proc => proc.pm2_env.status === 'online');
            }
            // Create ecosystem config
            const apps = filteredProcesses.map(proc => {
                const pm2Env = proc.pm2_env;
                return {
                    name: proc.name,
                    script: pm2Env.pm_exec_path,
                    cwd: pm2Env.pm_cwd,
                    instances: pm2Env.instances || 1,
                    exec_mode: pm2Env.exec_mode === 'cluster_mode' ? 'cluster' : 'fork',
                    autorestart: pm2Env.autorestart,
                    watch: pm2Env.watch,
                    ignore_watch: pm2Env.ignore_watch || [],
                    max_memory_restart: pm2Env.max_memory_restart || '150M',
                    env: pm2Env.env || {}
                };
            });
            const ecosystemConfig = `module.exports = {
  apps: ${JSON.stringify(apps, null, 2)}
};`;
            // Create the file (either at specified path or default location)
            const filePath = req.body.path || path_1.default.join(process.cwd(), 'ecosystem.config.js');
            fs_1.default.writeFileSync(filePath, ecosystemConfig);
            pm2_1.default.disconnect();
            res.json({
                success: true,
                message: 'Ecosystem file generated successfully',
                path: filePath
            });
        }
        catch (error) {
            pm2_1.default.disconnect();
            res.status(500).json({ error: error.message || 'Failed to generate ecosystem file' });
        }
    });
});
// Preview ecosystem.config.js content
router.get('/generate-ecosystem-preview', (req, res) => {
    pm2_1.default.connect(async (err) => {
        if (err) {
            console.error(err);
            return res.status(500).json({ error: 'Failed to connect to PM2' });
        }
        try {
            // Get all processes
            const listPromise = new Promise((resolve, reject) => {
                pm2_1.default.list((err, processList) => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    resolve(processList);
                });
            });
            const processList = await listPromise;
            // Create ecosystem config
            const apps = processList.map(proc => {
                const pm2Env = proc.pm2_env;
                return {
                    name: proc.name,
                    script: pm2Env.pm_exec_path,
                    cwd: pm2Env.pm_cwd,
                    instances: pm2Env.instances || 1,
                    exec_mode: pm2Env.exec_mode === 'cluster_mode' ? 'cluster' : 'fork',
                    autorestart: pm2Env.autorestart,
                    watch: pm2Env.watch,
                    ignore_watch: pm2Env.ignore_watch || [],
                    max_memory_restart: pm2Env.max_memory_restart || '150M',
                    env: pm2Env.env || {}
                };
            });
            const ecosystemConfig = `module.exports = {
  apps: ${JSON.stringify(apps, null, 2)}
};`;
            pm2_1.default.disconnect();
            res.json({
                success: true,
                content: ecosystemConfig
            });
        }
        catch (error) {
            pm2_1.default.disconnect();
            res.status(500).json({ error: error.message || 'Failed to generate ecosystem preview' });
        }
    });
});
// Detect project type
router.post('/detect-project', (req, res) => {
    const { projectPath } = req.body;
    if (!projectPath) {
        return res.status(400).json({ error: 'Project path is required' });
    }
    if (!fs_1.default.existsSync(projectPath)) {
        return res.status(400).json({ error: 'Project path does not exist' });
    }
    try {
        const projectType = ProjectSetupService_1.projectSetupService.detectProjectType(projectPath);
        const config = projectType ? ProjectSetupService_1.projectSetupService.getProjectConfig(projectType) : null;
        res.json({
            success: true,
            projectType,
            config: config ? {
                name: config.name,
                defaultConfig: config.defaultConfig,
                setupSteps: config.setup.steps.length
            } : null
        });
    }
    catch (error) {
        res.status(500).json({
            error: 'Failed to detect project type',
            details: error instanceof Error ? error.message : 'Unknown error'
        });
    }
});
// Setup project (without deployment)
router.post('/setup-project', async (req, res) => {
    const { projectPath, projectType } = req.body;
    if (!projectPath || !projectType) {
        return res.status(400).json({ error: 'Project path and type are required' });
    }
    if (!fs_1.default.existsSync(projectPath)) {
        return res.status(400).json({ error: 'Project path does not exist' });
    }
    try {
        const setupResult = await ProjectSetupService_1.projectSetupService.setupProject(projectPath, projectType);
        res.json({
            success: setupResult.success,
            steps: setupResult.steps,
            errors: setupResult.errors,
            warnings: setupResult.warnings,
            environment: setupResult.environment,
            interpreterPath: setupResult.interpreterPath
        });
    }
    catch (error) {
        res.status(500).json({
            error: 'Project setup failed',
            details: error instanceof Error ? error.message : 'Unknown error'
        });
    }
});
// Get supported project types
router.get('/project-types', (req, res) => {
    try {
        const types = ProjectSetupService_1.projectSetupService.getSupportedProjectTypes();
        const typeConfigs = types.map(type => {
            const config = ProjectSetupService_1.projectSetupService.getProjectConfig(type);
            return {
                type,
                name: config === null || config === void 0 ? void 0 : config.name,
                defaultConfig: config === null || config === void 0 ? void 0 : config.defaultConfig
            };
        });
        res.json({
            success: true,
            types: typeConfigs
        });
    }
    catch (error) {
        res.status(500).json({
            error: 'Failed to get project types',
            details: error instanceof Error ? error.message : 'Unknown error'
        });
    }
});
exports.default = router;
