import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { mkdtempSync, rmSync } from 'node:fs';
import ts from 'typescript';
import { executeSandboxCommand } from '../../runtime/sandbox/backend.js';
import {} from '../../runtime/sandbox/manager.js';
import { SandboxSessionRegistry } from '../../runtime/sandbox/session-registry.js';
import { summarizeError } from '../../utils/error-display.js';
import { REPL_TOOL_SCHEMA } from './schema.js';
function resolveHistoryPath(workspaceRoot) {
    return join(workspaceRoot, '.goodvibes', 'goodvibes', 'repl-history.json');
}
function createLocalExecPlan(workspaceRoot) {
    return {
        backend: 'local',
        command: process.env.SHELL || 'bash',
        args: ['-lc', 'true'],
        workspaceRoot,
        summary: 'local process exec',
    };
}
function loadHistory(historyPath) {
    try {
        return JSON.parse(readFileSync(historyPath, 'utf-8'));
    }
    catch {
        return [];
    }
}
function saveHistory(historyPath, entries) {
    mkdirSync(dirname(historyPath), { recursive: true });
    writeFileSync(historyPath, `${JSON.stringify(entries, null, 2)}\n`, 'utf-8');
}
function mapRuntimeToSandboxProfile(runtime) {
    switch (runtime) {
        case 'javascript': return 'eval-js';
        case 'typescript': return 'eval-ts';
        case 'python': return 'eval-py';
        case 'sql': return 'eval-sql';
        case 'graphql': return 'eval-graphql';
    }
}
async function evalJavaScriptInSandbox(expression, bindings, launchPlan, configManager, sandboxSessionRegistry, sessionId) {
    const payload = JSON.stringify({ expression, bindings });
    const runner = `
const payload = JSON.parse(process.env.GV_REPL_PAYLOAD ?? '{}');
const bindings = payload.bindings ?? {};
for (const [key, value] of Object.entries(bindings)) {
  globalThis[key] = value;
}
const value = eval(payload.expression);
process.stdout.write(typeof value === 'string' ? value : JSON.stringify(value));
`;
    const result = sessionId
        ? sandboxSessionRegistry.execute(sessionId, process.execPath, ['-e', runner], configManager, {
            timeoutMs: 1000,
            env: {
                ...process.env,
                GV_REPL_PAYLOAD: payload,
            },
        })
        : executeSandboxCommand(launchPlan, process.execPath, ['-e', runner], {
            timeoutMs: 1000,
            env: {
                ...process.env,
                GV_REPL_PAYLOAD: payload,
            },
        });
    if (result.status !== 0) {
        throw new Error((result.stderr || result.stdout || 'JavaScript eval failed.').trim());
    }
    return result.stdout.trim();
}
async function evalTypeScript(expression, bindings, configManager, sandboxSessionRegistry, launchPlan, sessionId) {
    const transpiled = ts.transpileModule(expression, {
        compilerOptions: {
            target: ts.ScriptTarget.ES2022,
            module: ts.ModuleKind.ES2022,
        },
    }).outputText;
    return evalJavaScriptInSandbox(transpiled, bindings, launchPlan, configManager, sandboxSessionRegistry, sessionId);
}
function evalPython(expression, workspaceRoot, configManager, sandboxSessionRegistry, launchPlan, sessionId) {
    const replTempBase = join(workspaceRoot, '.goodvibes', 'goodvibes', 'repl-temp');
    mkdirSync(replTempBase, { recursive: true });
    const tempRoot = mkdtempSync(join(replTempBase, 'gv-repl-py-'));
    const venvPath = join(tempRoot, 'venv');
    const pythonLaunchPlan = launchPlan.backend === 'local' ? {
        ...createLocalExecPlan(tempRoot),
        workspaceRoot: tempRoot,
    } : launchPlan;
    const create = sessionId
        ? sandboxSessionRegistry.execute(sessionId, 'python3', ['-m', 'venv', venvPath], configManager, { cwd: tempRoot })
        : executeSandboxCommand(pythonLaunchPlan, 'python3', ['-m', 'venv', venvPath], { cwd: tempRoot });
    if (create.status !== 0) {
        rmSync(tempRoot, { recursive: true, force: true });
        throw new Error(create.stderr || create.stdout || 'Failed to create ephemeral Python venv.');
    }
    const pythonBin = join(venvPath, 'bin', 'python');
    const run = sessionId
        ? sandboxSessionRegistry.execute(sessionId, pythonBin, ['-I', '-S', '-c', `import json\nresult = (${expression})\nprint(json.dumps(result))`], configManager, {
            cwd: tempRoot,
            timeoutMs: 5000,
        })
        : executeSandboxCommand(pythonLaunchPlan, pythonBin, ['-I', '-S', '-c', `import json\nresult = (${expression})\nprint(json.dumps(result))`], {
            cwd: tempRoot,
            timeoutMs: 5000,
        });
    rmSync(tempRoot, { recursive: true, force: true });
    if (run.status !== 0) {
        throw new Error((run.stderr || run.stdout || 'Python eval failed.').trim());
    }
    return run.stdout.trim();
}
async function evalSql(expression, configManager, sandboxSessionRegistry, launchPlan, sessionId) {
    const payload = JSON.stringify({ expression });
    const script = `
import { Database } from 'bun:sqlite';
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
const payload = JSON.parse(process.env.GV_REPL_PAYLOAD ?? '{}');
const db = new Database(':memory:');
db.exec("CREATE TABLE sandbox_eval (id INTEGER PRIMARY KEY, value TEXT);");
db.exec("INSERT INTO sandbox_eval (value) VALUES ('alpha'), ('beta');");
const rows = db.query(payload.expression).all();
process.stdout.write(JSON.stringify(rows));
`;
    const result = sessionId
        ? sandboxSessionRegistry.execute(sessionId, process.execPath, ['-e', script], configManager, {
            timeoutMs: 5000,
            env: {
                ...process.env,
                GV_REPL_PAYLOAD: payload,
            },
        })
        : executeSandboxCommand(launchPlan, process.execPath, ['-e', script], {
            timeoutMs: 5000,
            env: {
                ...process.env,
                GV_REPL_PAYLOAD: payload,
            },
        });
    if (result.status !== 0) {
        throw new Error((result.stderr || result.stdout || 'SQL eval failed.').trim());
    }
    return result.stdout.trim();
}
function evalGraphql(expression, configManager, sandboxSessionRegistry, launchPlan, sessionId) {
    const payload = JSON.stringify({ expression });
    const script = `
const payload = JSON.parse(process.env.GV_REPL_PAYLOAD ?? '{}');
const normalized = String(payload.expression ?? '').replace(/\\s+/g, ' ').trim();
const opMatch = normalized.match(/^(query|mutation|subscription)\\s+([A-Za-z0-9_]+)?/i);
const fields = [...normalized.matchAll(/\\b([A-Za-z_][A-Za-z0-9_]*)\\b/g)].map((match) => match[1]).slice(0, 12);
process.stdout.write(JSON.stringify({
  operation: opMatch?.[1]?.toLowerCase() ?? 'query',
  name: opMatch?.[2] ?? null,
  fields,
  normalized,
}));
`;
    const result = sessionId
        ? sandboxSessionRegistry.execute(sessionId, process.execPath, ['-e', script], configManager, {
            timeoutMs: 2000,
            env: {
                ...process.env,
                GV_REPL_PAYLOAD: payload,
            },
        })
        : executeSandboxCommand(launchPlan, process.execPath, ['-e', script], {
            timeoutMs: 2000,
            env: {
                ...process.env,
                GV_REPL_PAYLOAD: payload,
            },
        });
    if (result.status !== 0) {
        throw new Error((result.stderr || result.stdout || 'GraphQL eval failed.').trim());
    }
    return result.stdout.trim();
}
export function createReplTool(configManager, sandboxSessionRegistry) {
    return {
        definition: {
            name: 'repl',
            description: 'Evaluate bounded JavaScript, TypeScript, Python, SQL, and GraphQL snippets through controlled sandbox profiles.',
            parameters: REPL_TOOL_SCHEMA.parameters,
            sideEffects: ['exec', 'state'],
            concurrency: 'serial',
        },
        async execute(args) {
            if (!args || typeof args !== 'object' || typeof args.mode !== 'string') {
                return { success: false, error: 'Invalid args: mode is required.' };
            }
            const input = args;
            if (!input.workspaceRoot || input.workspaceRoot.trim().length === 0) {
                return { success: false, error: 'repl requires workspaceRoot.' };
            }
            const historyPath = resolveHistoryPath(input.workspaceRoot);
            const history = loadHistory(historyPath);
            const localExecPlan = createLocalExecPlan(input.workspaceRoot);
            if (input.mode === 'history') {
                return { success: true, output: JSON.stringify({ count: history.length, history }) };
            }
            if (!input.expression)
                return { success: false, error: 'eval requires expression.' };
            const runtime = input.runtime ?? 'javascript';
            const sandboxSession = await sandboxSessionRegistry.start(mapRuntimeToSandboxProfile(runtime), `repl:${runtime}`, configManager);
            try {
                let rendered = '';
                switch (runtime) {
                    case 'javascript':
                        rendered = await evalJavaScriptInSandbox(input.expression, input.bindings ?? {}, sandboxSession.launchPlan ?? localExecPlan, configManager, sandboxSessionRegistry, sandboxSession.id);
                        break;
                    case 'typescript':
                        rendered = await evalTypeScript(input.expression, input.bindings ?? {}, configManager, sandboxSessionRegistry, sandboxSession.launchPlan ?? localExecPlan, sandboxSession.id);
                        break;
                    case 'python':
                        rendered = evalPython(input.expression, input.workspaceRoot, configManager, sandboxSessionRegistry, sandboxSession.launchPlan ?? localExecPlan, sandboxSession.id);
                        break;
                    case 'sql':
                        rendered = await evalSql(input.expression, configManager, sandboxSessionRegistry, sandboxSession.launchPlan ?? localExecPlan, sandboxSession.id);
                        break;
                    case 'graphql':
                        rendered = evalGraphql(input.expression, configManager, sandboxSessionRegistry, sandboxSession.launchPlan ?? localExecPlan, sandboxSession.id);
                        break;
                }
                saveHistory(historyPath, [...history, {
                        ts: Date.now(),
                        runtime,
                        expression: input.expression,
                        sessionId: sandboxSession.id,
                        backend: sandboxSession.resolvedBackend ?? sandboxSession.backend,
                        launchSummary: sandboxSession.launchPlan?.summary,
                        result: rendered,
                    }]);
                return { success: true, output: rendered };
            }
            catch (error) {
                saveHistory(historyPath, [...history, {
                        ts: Date.now(),
                        runtime,
                        expression: input.expression,
                        sessionId: sandboxSession.id,
                        backend: sandboxSession.resolvedBackend ?? sandboxSession.backend,
                        launchSummary: sandboxSession.launchPlan?.summary,
                        error: summarizeError(error),
                    }]);
                return { success: false, error: summarizeError(error) };
            }
        },
    };
}
