/**
 * Sandbox globals for the headless sheet engine VM.
 *
 * Builds the global object injected into `vm.createContext()`.
 * Separated from sheet-exec.ts so the lifecycle API surface is
 * defined in one place and can be referenced by tests independently.
 */
import { readFile, writeFile } from 'node:fs/promises';
import { basename } from 'node:path';
import { errorCheck, getWorkbookSummary, setIBTextColors } from './wrappers/index.js';
// ---------------------------------------------------------------------------
// Lifecycle functions
// ---------------------------------------------------------------------------
/**
 * Build the workbook lifecycle functions exposed to agent code:
 * createWorkbook, loadWorkbook, getWorkbook, listWorkbooks, saveWorkbook,
 * closeWorkbook, and getActiveWorkbook. All returned workbooks are
 * wrapped in mutation-tracking proxies.
 */
function buildLifecycleFunctions(pool, tracker) {
    const createWorkbook = async (name) => {
        const wbName = await pool.createWorkbook(name);
        return tracker.track(pool.getWorkbook(wbName));
    };
    const loadWorkbook = async (path) => {
        const name = basename(path);
        if (pool.has(name)) {
            pool.activeWorkbookName = name;
            return tracker.track(pool.getWorkbook(name));
        }
        const buf = await readFile(path);
        await pool.openWorkbook(name, buf);
        pool.setSourcePath(name, path);
        return tracker.track(pool.getWorkbook(name));
    };
    const getWorkbook = (name) => {
        return tracker.track(pool.getWorkbook(name));
    };
    const listWorkbooks = () => {
        return pool.listWorkbooks();
    };
    const saveWorkbook = async (path, wb) => {
        const target = wb ??
            (() => {
                // Resolve by path basename first — if the path corresponds to a loaded
                // workbook, save that one regardless of which workbook is "active".
                const name = basename(path);
                if (pool.has(name))
                    return pool.getWorkbook(name);
                // Fall back to active workbook (e.g. saving a new workbook to a new path).
                if (!pool.activeWorkbookName)
                    throw new Error('No workbook open. Use createWorkbook() or loadWorkbook(path) first.');
                return pool.getWorkbook(pool.activeWorkbookName);
            })();
        if (typeof target.save === 'function') {
            await target.save(path);
            return path;
        }
        const exportFn = typeof target.toXlsx === 'function'
            ? target.toXlsx.bind(target)
            : typeof target.toBuffer === 'function'
                ? target.toBuffer.bind(target)
                : null;
        if (!exportFn) {
            throw new Error('Workbook does not support save(path), toXlsx(), or toBuffer().');
        }
        const buf = await exportFn();
        await writeFile(path, buf);
        return path;
    };
    const closeWorkbook = async (name) => {
        await pool.close(name);
    };
    const getActiveWorkbook = () => {
        if (!pool.activeWorkbookName) {
            throw new Error('No workbook open. Use createWorkbook() or loadWorkbook(path) first.');
        }
        return tracker.track(pool.getWorkbook(pool.activeWorkbookName));
    };
    return {
        createWorkbook,
        loadWorkbook,
        getWorkbook,
        listWorkbooks,
        saveWorkbook,
        closeWorkbook,
        getActiveWorkbook
    };
}
// ---------------------------------------------------------------------------
// Full sandbox object
// ---------------------------------------------------------------------------
/**
 * Assemble the full global object for the VM sandbox.
 *
 * Includes workbook lifecycle functions, convenience getters (`workbook`,
 * `worksheet`), file I/O helpers, wrapper utilities (errorCheck,
 * setIBTextColors, getWorkbookSummary), a captured console, and
 * whitelisted JS built-ins.
 */
export function buildSandbox(deps) {
    const { pool, tracker, console: sandboxConsole } = deps;
    const lifecycle = buildLifecycleFunctions(pool, tracker);
    return {
        // Workbook lifecycle
        createWorkbook: lifecycle.createWorkbook,
        loadWorkbook: lifecycle.loadWorkbook,
        getWorkbook: lifecycle.getWorkbook,
        listWorkbooks: lifecycle.listWorkbooks,
        saveWorkbook: lifecycle.saveWorkbook,
        closeWorkbook: lifecycle.closeWorkbook,
        // Convenience: active workbook/worksheet (lazy getters, tracked)
        get workbook() {
            return lifecycle.getActiveWorkbook();
        },
        get worksheet() {
            return lifecycle.getActiveWorkbook().activeSheet;
        },
        // File I/O — bridge data between bash and execute_code
        readFile: (path) => readFile(path, 'utf-8'),
        writeFile: (path, data) => writeFile(path, data, 'utf-8'),
        // Wrapper utilities
        errorCheck: async (ranges) => {
            const wb = lifecycle.getActiveWorkbook();
            return errorCheck(wb, ranges);
        },
        setIBTextColors: async (range, ignoredConstants, colors) => {
            const ws = lifecycle.getActiveWorkbook().activeSheet;
            return setIBTextColors(ws, range, { ignoredConstants, colors });
        },
        getWorkbookSummary: async () => {
            const wb = lifecycle.getActiveWorkbook();
            return getWorkbookSummary(wb);
        },
        console: sandboxConsole,
        // Standard globals
        Math,
        Date,
        JSON,
        Array,
        Object,
        String,
        Number,
        Boolean,
        RegExp,
        Map,
        Set,
        Promise,
        Error,
        TypeError,
        RangeError,
        parseInt,
        parseFloat,
        isNaN,
        isFinite,
        encodeURIComponent,
        decodeURIComponent,
        setTimeout,
        clearTimeout,
        Buffer,
        URL
    };
}
//# sourceMappingURL=sandbox-globals.js.map