"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 path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const https_1 = __importDefault(require("https"));
// @group Utilities : Read the current installed version from package.json
const getCurrentVersion = () => {
    try {
        // Try the package root (works when run from source or dist)
        const candidates = [
            path_1.default.resolve(__dirname, '../../../package.json'),
            path_1.default.resolve(__dirname, '../../package.json'),
            path_1.default.resolve(process.cwd(), 'package.json'),
        ];
        for (const p of candidates) {
            if (fs_1.default.existsSync(p)) {
                const pkg = JSON.parse(fs_1.default.readFileSync(p, 'utf8'));
                if (pkg.name === 'ezpm2gui')
                    return pkg.version;
            }
        }
    }
    catch {
        // fall through
    }
    return '0.0.0';
};
// @group Utilities : Fetch latest version info from npm registry (no external deps)
const fetchNpmLatest = () => new Promise((resolve, reject) => {
    const req = https_1.default.get('https://registry.npmjs.org/ezpm2gui/latest', { headers: { Accept: 'application/json' } }, (res) => {
        let data = '';
        res.on('data', (chunk) => { data += chunk; });
        res.on('end', () => {
            var _a;
            try {
                const json = JSON.parse(data);
                resolve({
                    version: json.version,
                    description: json.description,
                    publishedAt: (_a = json.time) === null || _a === void 0 ? void 0 : _a.modified,
                });
            }
            catch {
                reject(new Error('Failed to parse npm registry response'));
            }
        });
    });
    req.on('error', reject);
    req.setTimeout(8000, () => { req.destroy(); reject(new Error('npm registry request timed out')); });
});
// @group Utilities : Compare semver strings — returns true if b is newer than a
const isNewer = (current, latest) => {
    const parse = (v) => v.replace(/^v/, '').split('.').map(Number);
    const [cMaj, cMin, cPat] = parse(current);
    const [lMaj, lMin, lPat] = parse(latest);
    if (lMaj !== cMaj)
        return lMaj > cMaj;
    if (lMin !== cMin)
        return lMin > cMin;
    return lPat > cPat;
};
const router = (0, express_1.Router)();
// @group CheckUpdate : GET /api/update/check — returns current vs latest npm version
router.get('/check', async (_req, res) => {
    try {
        const currentVersion = getCurrentVersion();
        const { version: latestVersion, publishedAt } = await fetchNpmLatest();
        const updateAvailable = isNewer(currentVersion, latestVersion);
        const result = {
            currentVersion,
            latestVersion,
            updateAvailable,
            publishedAt,
        };
        res.json({ success: true, data: result });
    }
    catch (err) {
        console.error('Update check failed:', err);
        res.status(503).json({ success: false, error: err.message || 'Failed to reach npm registry' });
    }
});
// @group InstallUpdate : POST /api/update/install — installs ezpm2gui@latest globally
// Streams progress lines as newline-delimited JSON (ndjson) so the client can read incrementally.
router.post('/install', (req, res) => {
    res.setHeader('Content-Type', 'application/x-ndjson');
    res.setHeader('Transfer-Encoding', 'chunked');
    res.setHeader('Cache-Control', 'no-cache');
    res.flushHeaders();
    const send = (type, message) => {
        res.write(JSON.stringify({ type, message }) + '\n');
    };
    send('log', 'Starting update — running npm install -g ezpm2gui@latest...');
    // Use `npm` with execFile for safety — no shell injection possible
    const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
    const child = (0, child_process_1.spawn)(npmCmd, ['install', '-g', 'ezpm2gui@latest'], {
        stdio: ['ignore', 'pipe', 'pipe'],
        shell: false,
    });
    child.stdout.on('data', (chunk) => {
        chunk.toString().split('\n').filter(Boolean).forEach((line) => send('log', line));
    });
    child.stderr.on('data', (chunk) => {
        // npm writes progress to stderr — treat as log unless it's an actual error keyword
        const text = chunk.toString();
        const isError = /^npm (ERR|error)/i.test(text.trim());
        text.split('\n').filter(Boolean).forEach((line) => send(isError ? 'error' : 'log', line));
    });
    child.on('close', (code) => {
        if (code === 0) {
            send('done', 'Update installed successfully. Reload the page to use the new frontend. Restart the server to apply backend changes.');
        }
        else {
            send('fail', `npm exited with code ${code}. Update may have failed.`);
        }
        res.end();
    });
    child.on('error', (err) => {
        send('fail', `Failed to run npm: ${err.message}`);
        res.end();
    });
});
// @group RestartServer : POST /api/update/restart — graceful server restart (relies on process manager to respawn)
router.post('/restart', (_req, res) => {
    res.json({ success: true, message: 'Server will restart in 1 second.' });
    setTimeout(() => {
        console.log('[ezpm2gui] Graceful restart triggered via API.');
        process.exit(0);
    }, 1000);
});
exports.default = router;
