"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = void 0;
exports.createReplContext = createReplContext;
exports.evaluateReplCode = evaluateReplCode;
exports.runLocalAppRepl = runLocalAppRepl;
exports.tryGet = tryGet;
const node_os_1 = require("node:os");
const node_path_1 = require("node:path");
const node_repl_1 = require("node:repl");
const node_util_1 = require("node:util");
const database_1 = require("../database");
function createReplContext(app) {
    const resolve = (token) => app.get(token);
    return {
        app,
        container: app.container,
        config: app.config,
        db: tryGet(app, database_1.BaseDatabase),
        resolve,
        r: resolve,
        $: resolve,
        process,
        Buffer,
        inspect: node_util_1.inspect
    };
}
async function evaluateReplCode(context, code, colors = false) {
    const logs = [];
    const capture = (...args) => logs.push(args.map(item => (typeof item === 'string' ? item : (0, node_util_1.inspect)(item, { depth: 4, colors }))).join(' '));
    const localConsole = {
        log: capture,
        warn: capture,
        error: capture,
        info: capture,
        debug: capture
    };
    try {
        const fn = new Function('context', 'console', `with (context) { return eval(${JSON.stringify(code)}) }`);
        let result = fn(context, localConsole);
        if (result && typeof result === 'object' && typeof result.then === 'function')
            result = await result;
        const resultText = result === undefined ? '' : (0, node_util_1.inspect)(result, { depth: 4, colors });
        return { output: [...logs, resultText].filter(Boolean).join('\n') };
    }
    catch (error) {
        return {
            output: logs.join('\n'),
            error: error instanceof Error ? (error.stack ?? error.message) : String(error)
        };
    }
}
async function runLocalAppRepl(app, args) {
    const evalCode = takeEvalArgument(args);
    if (args.length)
        throw new Error(`repl does not accept arguments: ${args.join(' ')}`);
    try {
        await app.start();
        if (evalCode !== undefined) {
            const result = await evaluateReplCode(createReplContext(app), evalCode, !!process.stdout.isTTY);
            if (result.output)
                process.stdout.write(`${result.output}\n`);
            if (result.error) {
                const error = new Error(result.error);
                error.stack = result.error;
                throw error;
            }
            return;
        }
        await openLocalRepl(app);
    }
    finally {
        await app.stop();
    }
}
function openLocalRepl(app) {
    const server = (0, node_repl_1.start)({
        prompt: 'tsf> ',
        useColors: !!process.stdout.isTTY,
        ignoreUndefined: true
    });
    Object.assign(server.context, createReplContext(app));
    if (process.stdin.isTTY && process.env.NODE_REPL_HISTORY !== '') {
        const historyPath = process.env.NODE_REPL_HISTORY || (0, node_path_1.join)((0, node_os_1.homedir)(), '.tsf_repl_history');
        server.setupHistory(historyPath, error => {
            if (error)
                process.stderr.write(`Could not load REPL history: ${error.message}\n`);
        });
    }
    return new Promise(resolve => server.once('exit', resolve));
}
function takeEvalArgument(args) {
    for (let index = 0; index < args.length; index++) {
        const arg = args[index];
        if (arg === '--eval' || arg === '-e') {
            const value = args[index + 1];
            if (value === undefined)
                throw new Error(`${arg} requires JavaScript source`);
            args.splice(index, 2);
            return value;
        }
        if (arg.startsWith('--eval=')) {
            args.splice(index, 1);
            return arg.slice('--eval='.length);
        }
    }
    return undefined;
}
function tryGet(app, token) {
    try {
        return app.get(token);
    }
    catch {
        return undefined;
    }
}
exports.__tsfTypeAliases = JSON.parse("[1,{\"ReplEvaluation\":{\"kind\":18,\"typeName\":\"ReplEvaluation\",\"types\":[{\"kind\":20,\"name\":\"output\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"error\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true}]}}]")[1];
//# sourceMappingURL=repl.js.map