// index.js — Greenshades native N-API loader (lazy).
//
// The Zig backend's napi_register_module_v1 entry point performs a
// ServiceCellPool.init that forks 4 child processes. On non-Linux, in
// containers without seccomp, or in test runners that don't intend to
// exercise the native code, this fork sequence can corrupt glibc's heap
// or simply block for ~4 seconds (one blocked read per cell).
//
// To avoid loading the binary on import (which would run that init at
// unpredictable times), the binary is loaded LAZILY — only when a
// caller actually accesses an export. Detection at module-load time
// uses a synchronous fs stat call to confirm the prebuild exists.
//
// Env vars:
//   GREENSHADES_ZIG_NATIVE=1 — prefer a freshly-built zig-out/ binary
//                              over the bundled prebuild
//   GREENSHADES_ZIG_SKIP=1   — disable native loading entirely (use
//                              synthetic JS-only stubs for tests)
'use strict';

const os = require('os');
const fs = require('fs');
const path = require('path');

function platformArch() {
    const p = os.platform();
    const a = os.arch();
    if (p === 'linux' && a === 'x64') return 'x86_64-linux';
    if (p === 'linux' && a === 'arm64') return 'aarch64-linux';
    return null;
}

const platformKey = platformArch();
const useBuilt = process.env.GREENSHADES_ZIG_NATIVE === '1';
const skipNative = process.env.GREENSHADES_ZIG_SKIP === '1';

function candidatePath() {
    if (useBuilt) {
        const built = path.join(__dirname, '..', 'zig-out', 'greenshades_backend.node');
        if (fs.existsSync(built)) return built;
        const projRoot = path.join(__dirname, '..', 'greenshades_backend.node');
        if (fs.existsSync(projRoot)) return projRoot;
    }
    if (!platformKey) return null;
    const prebuild = path.join(__dirname, 'prebuilds', platformKey, 'greenshades_backend.node');
    return fs.existsSync(prebuild) ? prebuild : null;
}

function ensureLoaded() {
    if (module.exports.__loaded) return true;
    const candidate = candidatePath();
    if (!candidate) return false;
    const { dlopen } = require('process');
    const constants = process.binding('constants');
    const RTLD_LAZY = constants.os.dlopen.RTLD_LAZY;
    const RTLD_LOCAL = constants.os.dlopen.RTLD_LOCAL;
    try {
        const mod = { exports: {} };
        dlopen(mod, candidate, RTLD_LAZY | RTLD_LOCAL);
        if (typeof mod.exports.createBackend === 'function') {
            for (const k of Object.keys(mod.exports)) {
                module.exports[k] = mod.exports[k];
            }
            module.exports.__loaded = true;
            return true;
        }
    } catch (_) {}
    return false;
}

if (!skipNative) {
    const candidate = candidatePath();
    module.exports.__nativeCandidatePath = candidate;
    module.exports.__nativeCandidatePresent = !!candidate;
    module.exports.__nativeAvailable = false;
    module.exports.__loaded = false;
}

module.exports.__platformKey = platformKey;
module.exports.__ensureLoaded = ensureLoaded;

function notLoadedError() {
    return new Error([
        'Greenshades native addon not available for ' + (platformKey || os.platform() + '-' + os.arch()) + '.',
        '',
        'To build from source:',
        '  1. Install Zig 0.16+',
        '  2. Run: cd zig-native && zig build napi',
        '  3. Copy zig-out/greenshades_backend.node to:',
        '     zig-native/node/prebuilds/' + (platformKey || 'YOUR_PLATFORM') + '/greenshades_backend.node',
    ].join('\n'));
}

const handler = {
    get(target, prop) {
        if (typeof prop === 'string' && prop.startsWith('__')) {
            return target[prop];
        }
        if (typeof prop === 'string' && target[prop] === undefined) {
            if (!ensureLoaded()) throw notLoadedError();
            return target[prop];
        }
        return target[prop];
    },
};

module.exports = new Proxy(module.exports, handler);

