"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CLI_MIDDLEWARE = void 0;
const chalk_1 = __importDefault(require("chalk"));
const versionUtil_1 = require("./commands/commandUtil/versionUtil");
const logLineMessaging_1 = require("@mablhq-internal/runtime/core/messaging/logLineMessaging");
const messaging_1 = require("@mablhq-internal/runtime/core/messaging/messaging");
const loggingProvider_1 = require("@mablhq-internal/runtime/providers/logging/loggingProvider");
const analytics_1 = require("@mablhq-internal/runtime/util/analytics");
const pureUtil_1 = require("@mablhq-internal/runtime/util/pureUtil");
const https_1 = __importDefault(require("https"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const cliPackage = require('./package.json');
const stripAnsi = require('strip-ansi');
const UPDATE_CHECK_INTERVAL_MILLISECONDS = 24 * 60 * 60 * 1000;
const UPDATE_CHECK_TIMEOUT_MILLISECONDS = 5000;
const MAX_RESPONSE_SIZE_BYTES = 10 * 1024;
const MIN_SUPPORTED_NODE_VERSION = (0, versionUtil_1.extractNodeVersionTuple)(cliPackage?.engines?.node);
exports.CLI_MIDDLEWARE = [
    () => {
        (0, logLineMessaging_1.registerConsoleLoggerForOutput)(messaging_1.mablEventEmitter);
    },
    warnOnUnsupportedNodeVersion,
    async (argv) => (0, analytics_1.trackCliEvent)(argv._, (0, pureUtil_1.extractKeyCountsFromArgs)(argv)),
    runUpdateCheck,
];
function warnOnUnsupportedNodeVersion() {
    const nodeVersion = (0, versionUtil_1.extractNodeVersionTuple)(process.version);
    if ((0, versionUtil_1.compareNodeVersions)(nodeVersion, MIN_SUPPORTED_NODE_VERSION) < 0 &&
        !isMcpProcess()) {
        loggingProvider_1.logger.info(chalk_1.default.bgYellow.black(`WARNING: Unsupported Node.js detected (`) +
            chalk_1.default.bgYellow.bold.white((0, versionUtil_1.nodeVersionToString)(nodeVersion)) +
            chalk_1.default.bgYellow.black(`). \nmabl-cli functionality may be limited, please update to `) +
            chalk_1.default.bgYellow.bold.white((0, versionUtil_1.nodeVersionToString)(MIN_SUPPORTED_NODE_VERSION)) +
            chalk_1.default.bgYellow.black(' or later.\n'));
    }
}
async function runUpdateCheck() {
    if (!process.stdout.isTTY || isMcpProcess() || isNpmOrYarnScript()) {
        return;
    }
    try {
        const latestVersion = await checkForUpdate(cliPackage.name, cliPackage.version, UPDATE_CHECK_INTERVAL_MILLISECONDS);
        if (latestVersion) {
            const message = [
                '',
                `Update available! ${chalk_1.default.dim(cliPackage.version)} → ${chalk_1.default.green(latestVersion)}`,
                `Run ${chalk_1.default.cyan(`npm i -g ${cliPackage.name}`)} to update`,
                '',
            ];
            console.error(borderedText(message.join('\n')));
        }
    }
    catch {
    }
}
async function checkForUpdate(packageName, currentVersion, checkInterval) {
    const configDir = process.env.XDG_CONFIG_HOME ||
        path_1.default.join(os_1.default.homedir(), '.config', 'mabl-cli');
    const configFile = path_1.default.join(configDir, `${packageName.replace('@', '').replace('/', '__')}.json`);
    try {
        if (fs_1.default.existsSync(configFile)) {
            const data = JSON.parse(fs_1.default.readFileSync(configFile, 'utf8'));
            if (data.lastUpdateCheck > Date.now() - checkInterval) {
                return undefined;
            }
        }
    }
    catch {
    }
    const latestVersion = await getLatestVersion(packageName);
    try {
        if (!fs_1.default.existsSync(configDir)) {
            fs_1.default.mkdirSync(configDir, { recursive: true });
        }
        fs_1.default.writeFileSync(configFile, JSON.stringify({ lastUpdateCheck: Date.now() }));
    }
    catch {
    }
    if (isNewerVersion(latestVersion, currentVersion)) {
        return latestVersion;
    }
    return undefined;
}
function isNewerVersion(latest, current) {
    const stripPrerelease = (v) => v.split('-')[0];
    const latestParts = stripPrerelease(latest).split('.').map(Number);
    const currentParts = stripPrerelease(current).split('.').map(Number);
    for (let i = 0; i < Math.max(latestParts.length, currentParts.length); i++) {
        const l = latestParts[i] || 0;
        const c = currentParts[i] || 0;
        if (Number.isNaN(l) || Number.isNaN(c)) {
            return false;
        }
        if (l > c) {
            return true;
        }
        if (l < c) {
            return false;
        }
    }
    return false;
}
function getLatestVersion(packageName) {
    return new Promise((resolve, reject) => {
        const url = `https://registry.npmjs.org/-/package/${packageName}/dist-tags`;
        const request = https_1.default.get(url, (res) => {
            if (res.statusCode !== 200) {
                reject(new Error(`HTTP ${res.statusCode}`));
                return;
            }
            let body = '';
            let receivedBytes = 0;
            res.on('data', (chunk) => {
                receivedBytes += chunk.length;
                if (receivedBytes > MAX_RESPONSE_SIZE_BYTES) {
                    request.destroy();
                    reject(new Error('Response too large'));
                    return;
                }
                body += chunk;
            });
            res.on('end', () => {
                try {
                    const json = JSON.parse(body);
                    if (json.latest) {
                        resolve(json.latest);
                    }
                    else {
                        reject(new Error('No latest version found'));
                    }
                }
                catch {
                    reject(new Error('Could not parse response'));
                }
            });
        });
        request.on('error', reject);
        request.setTimeout(UPDATE_CHECK_TIMEOUT_MILLISECONDS, () => {
            request.destroy();
            reject(new Error('Request timeout'));
        });
    });
}
function borderedText(text) {
    const lines = text.split('\n');
    const width = Math.max(...lines.map((l) => stripAnsi(l).length));
    const border = chalk_1.default.yellow;
    const res = [border(`┌${'─'.repeat(width + 2)}┐`)];
    for (const line of lines) {
        const padding = ' '.repeat(width - stripAnsi(line).length);
        res.push(`${border('│')} ${line}${padding} ${border('│')}`);
    }
    res.push(border(`└${'─'.repeat(width + 2)}┘`));
    return res.join('\n');
}
function isMcpProcess() {
    return process.argv.includes('mcp');
}
function isNpmOrYarnScript() {
    const userAgent = process.env.npm_config_user_agent;
    const packageJson = process.env.npm_package_json;
    const isNpm = Boolean(userAgent?.startsWith('npm')) ||
        Boolean(packageJson?.endsWith('package.json'));
    const isYarn = Boolean(userAgent?.startsWith('yarn'));
    return isNpm || isYarn;
}
