/**
 * Safe hot-reload protocol for plugins.
 *
 * Implements the 6-phase hot-reload sequence:
 *   1. Quiesce   — stop accepting new work from the plugin
 *   2. Unregister — remove plugin's registrations (commands, tools, hooks)
 *   3. Unload    — deactivate and clean up the old plugin instance
 *   4. Reload    — load the new version with a cache-bust timestamp
 *   5. Re-register — new instance calls init/activate (registers naturally)
 *   6. Health check → active (healthy) or degraded (unhealthy)
 */
import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
/** Default trivial health check — always returns healthy. */
async function defaultHealthCheck(name) {
    return {
        healthy: true,
        message: `${name}: health check passed (default)`,
        durationMs: 0,
    };
}
/**
 * runHotReload — Execute the safe 6-phase hot-reload protocol for a single
 * plugin.
 *
 * @param name      - Plugin name.
 * @param manifest  - Current manifest for the plugin.
 * @param pluginDir - Absolute path to the plugin directory.
 * @param deps      - Loader dependencies (runtime bus, registries, etc.).
 * @param lcm       - PluginLifecycleManager to track state transitions.
 * @param options   - Host-side callbacks and configuration.
 * @returns HotReloadResult describing the outcome.
 */
export async function runHotReload(name, manifest, pluginDir, deps, lcm, options) {
    const startTs = Date.now();
    const healthCheck = options.healthCheck ?? defaultHealthCheck;
    const timeoutMs = options.healthCheckTimeoutMs ?? 5000;
    const record = lcm.getRecord(name);
    if (!record) {
        return {
            success: false,
            failedPhase: 'quiesce',
            error: `Plugin '${name}' is not tracked by the lifecycle manager`,
            durationMs: Date.now() - startTs,
            degraded: false,
        };
    }
    logger.info(`[plugin-hot-reload] ${name}: starting hot-reload`);
    // ── Phase 1: Quiesce ────────────────────────────────────────────────────
    // Mark the plugin as reloading to signal to callers to defer new work.
    // (The PluginLifecycleRecord.reloading flag is set, but state is not changed.)
    // In a future implementation this phase could drain in-flight requests.
    try {
        // Access via cast since reloading is a mutable field on the record.
        const mutableRecord = record;
        mutableRecord.reloading = true;
        logger.debug(`[plugin-hot-reload] ${name}: phase 1/6 quiesced`);
    }
    catch (err) {
        return failure('quiesce', summarizeError(err), startTs);
    }
    // ── Phase 2: Prepare unregister ──────────────────────────────────────────
    // The existing plugin's cleanup callbacks handle un-registration during
    // unload, so there is no separate hook dispatch here.
    logger.debug(`[plugin-hot-reload] ${name}: phase 2/6 unregister scheduled with unload cleanup`);
    // ── Phase 3: Unload ─────────────────────────────────────────────────────
    try {
        const loaded = options.getLoadedPlugin(name);
        if (loaded) {
            const { unloadPlugin } = await import('../../plugins/loader.js');
            await unloadPlugin(loaded);
        }
        options.removeLoadedPlugin(name);
        logger.debug(`[plugin-hot-reload] ${name}: phase 3/6 unloaded`);
    }
    catch (err) {
        return failure('unload', summarizeError(err), startTs);
    }
    // ── Phase 4 + 5: Reload + Re-register ──────────────────────────────────
    // loadPlugin calls init() and activate() which re-registers everything.
    let reloadedPlugin = null;
    try {
        const { loadPlugin } = await import('../../plugins/loader.js');
        const cacheBust = Date.now();
        reloadedPlugin = await loadPlugin({ manifest, pluginDir }, deps, cacheBust);
        if (!reloadedPlugin) {
            return failure('reload', 'loadPlugin returned null', startTs);
        }
        options.storeLoadedPlugin(name, reloadedPlugin);
        logger.debug(`[plugin-hot-reload] ${name}: phases 4+5/6 reloaded + re-registered`);
    }
    catch (err) {
        return failure('reload', summarizeError(err), startTs);
    }
    // ── Phase 6: Health check ────────────────────────────────────────────────
    let healthResult;
    try {
        healthResult = await Promise.race([
            healthCheck(name),
            new Promise((_, reject) => setTimeout(() => reject(new Error(`health check timed out after ${timeoutMs}ms`)), timeoutMs)),
        ]);
    }
    catch (err) {
        healthResult = {
            healthy: false,
            message: summarizeError(err),
            durationMs: Date.now() - startTs,
        };
    }
    // Clear reloading flag.
    try {
        const mutableRecord = lcm.getRecord(name);
        if (mutableRecord)
            mutableRecord.reloading = false;
    }
    catch { /* non-fatal */ }
    if (healthResult.healthy) {
        logger.info(`[plugin-hot-reload] ${name}: hot-reload complete — active (${Date.now() - startTs}ms)`);
        return {
            success: true,
            durationMs: Date.now() - startTs,
            degraded: false,
        };
    }
    else {
        // Plugin loaded but health check failed → degraded.
        lcm.degradePlugin(name, `Health check failed: ${healthResult.message}`);
        logger.warn(`[plugin-hot-reload] ${name}: hot-reload complete — degraded (${healthResult.message})`);
        return {
            success: true, // reload succeeded; just in degraded state
            durationMs: Date.now() - startTs,
            degraded: true,
        };
    }
}
/** Build a failure result for a named phase. */
function failure(phase, error, startTs) {
    logger.error(`[plugin-hot-reload] phase '${String(phase)}' failed: ${error}`);
    return {
        success: false,
        failedPhase: phase,
        error,
        durationMs: Date.now() - startTs,
        degraded: false,
    };
}
