"use strict";
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
 * WASM Runtime Management
 *
 * Handles WASM runtime initialization, module loading,
 * and instance lifecycle management for Signal K WASM plugins.
 *
 * This is the main entry point that coordinates the various loaders
 * and bindings for different WASM plugin formats.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WasmRuntime = exports.wasmWeatherProviders = exports.wasmResourceProviders = exports.detectWasmFormat = void 0;
exports.getWasmRuntime = getWasmRuntime;
exports.initializeWasmRuntime = initializeWasmRuntime;
exports.resetWasmRuntime = resetWasmRuntime;
const fs = __importStar(require("fs"));
const debug_1 = __importDefault(require("debug"));
// Re-export utilities
var format_detection_1 = require("./utils/format-detection");
Object.defineProperty(exports, "detectWasmFormat", { enumerable: true, get: function () { return format_detection_1.detectWasmFormat; } });
// Import loaders
const standard_loader_1 = require("./loaders/standard-loader");
// Import bindings
const resource_provider_1 = require("./bindings/resource-provider");
Object.defineProperty(exports, "wasmResourceProviders", { enumerable: true, get: function () { return resource_provider_1.wasmResourceProviders; } });
const weather_provider_1 = require("./bindings/weather-provider");
Object.defineProperty(exports, "wasmWeatherProviders", { enumerable: true, get: function () { return weather_provider_1.wasmWeatherProviders; } });
// Import utilities
const format_detection_2 = require("./utils/format-detection");
const debug = (0, debug_1.default)('signalk:wasm:runtime');
class WasmRuntime {
    instances = new Map();
    enabled = true;
    constructor() {
        debug('Initializing WASM runtime');
    }
    /**
     * Check if WASM support is enabled
     */
    isEnabled() {
        return this.enabled;
    }
    /**
     * Enable or disable WASM plugin support
     */
    setEnabled(enabled) {
        this.enabled = enabled;
        debug(`WASM support ${enabled ? 'enabled' : 'disabled'}`);
    }
    /**
     * Load and instantiate a WASM plugin module
     */
    async loadPlugin(pluginId, wasmPath, vfsRoot, capabilities, app) {
        if (!this.enabled) {
            throw new Error('WASM support is disabled');
        }
        debug(`Loading WASM plugin: ${pluginId} from ${wasmPath}`);
        try {
            // Ensure VFS root exists
            if (!fs.existsSync(vfsRoot)) {
                fs.mkdirSync(vfsRoot, { recursive: true });
            }
            // Load WASM binary
            debug(`Reading WASM file: ${wasmPath}`);
            const wasmBuffer = fs.readFileSync(wasmPath);
            debug(`WASM file size: ${wasmBuffer.length} bytes`);
            const wasmFormat = (0, format_detection_2.detectWasmFormat)(wasmBuffer);
            debug(`Detected WASM format: ${wasmFormat}`);
            if (wasmFormat !== 'wasi-p1') {
                throw new Error(`Unsupported WASM format: ${wasmFormat}. Only WASI P1 plugins (AssemblyScript/Rust) are supported.`);
            }
            // Load standard WASI P1 plugin (AssemblyScript or Rust)
            const pluginInstance = await (0, standard_loader_1.loadStandardPlugin)(pluginId, wasmPath, wasmBuffer, vfsRoot, capabilities, app);
            // Store the instance
            this.instances.set(pluginId, pluginInstance);
            debug(`Successfully loaded WASM plugin: ${pluginId}`);
            return pluginInstance;
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            debug(`Failed to load WASM plugin ${pluginId}: ${errorMsg}`);
            throw new Error(`Failed to load WASM plugin ${pluginId}: ${errorMsg}`);
        }
    }
    /**
     * Unload a WASM plugin instance
     * @param pluginId The plugin ID to unload
     * @param app Optional Signal K app reference for proper API cleanup
     */
    async unloadPlugin(pluginId, app) {
        const instance = this.instances.get(pluginId);
        if (!instance) {
            debug(`Plugin ${pluginId} not found in loaded instances`);
            return;
        }
        debug(`Unloading WASM plugin: ${pluginId}`);
        try {
            // Call stop if available
            if (instance.exports.stop) {
                instance.exports.stop();
            }
            // Clean up resource provider registrations for this plugin
            // Pass app to also unregister from ResourcesApi
            (0, resource_provider_1.cleanupResourceProviders)(pluginId, app);
            // Clean up weather provider registrations for this plugin
            // Pass app to also unregister from WeatherApi
            (0, weather_provider_1.cleanupWeatherProviders)(pluginId, app);
            // Remove from instances
            this.instances.delete(pluginId);
            // Let GC clean up the instance
            debug(`Successfully unloaded WASM plugin: ${pluginId}`);
        }
        catch (error) {
            const errorMsg = error instanceof Error ? error.message : String(error);
            debug(`Error unloading WASM plugin ${pluginId}: ${errorMsg}`);
            throw error;
        }
    }
    /**
     * Reload a WASM plugin (unload + load)
     */
    async reloadPlugin(pluginId) {
        const oldInstance = this.instances.get(pluginId);
        if (!oldInstance) {
            throw new Error(`Plugin ${pluginId} not loaded`);
        }
        const { wasmPath, vfsRoot, capabilities } = oldInstance;
        // Unload old instance
        await this.unloadPlugin(pluginId);
        // Load new instance
        return this.loadPlugin(pluginId, wasmPath, vfsRoot, capabilities);
    }
    /**
     * Get a loaded plugin instance
     */
    getInstance(pluginId) {
        return this.instances.get(pluginId);
    }
    /**
     * Get all loaded plugin instances
     */
    getAllInstances() {
        return Array.from(this.instances.values());
    }
    /**
     * Check if a plugin is loaded
     */
    isPluginLoaded(pluginId) {
        return this.instances.has(pluginId);
    }
    /**
     * Shutdown the WASM runtime and unload all plugins
     */
    async shutdown() {
        debug('Shutting down WASM runtime');
        const pluginIds = Array.from(this.instances.keys());
        for (const pluginId of pluginIds) {
            try {
                await this.unloadPlugin(pluginId);
            }
            catch (error) {
                debug(`Error unloading plugin ${pluginId} during shutdown:`, error);
            }
        }
        this.instances.clear();
        debug('WASM runtime shutdown complete');
    }
}
exports.WasmRuntime = WasmRuntime;
// Global singleton instance
let runtimeInstance = null;
/**
 * Get the global WASM runtime instance
 */
function getWasmRuntime() {
    if (!runtimeInstance) {
        runtimeInstance = new WasmRuntime();
    }
    return runtimeInstance;
}
/**
 * Initialize the WASM runtime
 */
function initializeWasmRuntime() {
    if (runtimeInstance) {
        debug('WASM runtime already initialized');
        return runtimeInstance;
    }
    runtimeInstance = new WasmRuntime();
    return runtimeInstance;
}
/**
 * Reset the WASM runtime singleton (for hotplug support)
 * This should be called after shutdown to allow re-initialization
 */
function resetWasmRuntime() {
    debug('Resetting WASM runtime singleton');
    runtimeInstance = null;
}
//# sourceMappingURL=wasm-runtime.js.map