import * as plugins from './plugins.js';
import * as interfaces from '../dist_ts_interfaces/index.js';
import { logger } from './logging.js';
const DEFAULT_CONNECTION_OPTIONS = {
    timeoutMs: 30000,
    maxRetries: 10,
    initialDelayMs: 500,
    maxDelayMs: 5000,
    backoffMultiplier: 1.5,
};
export class ActionManager {
    deesComms = new plugins.deesComms.DeesComms();
    statusCallbacks = new Set();
    constructor() {
        // lets define handlers on the client/tab side
        this.deesComms.createTypedHandler('serviceworker_newVersion', async (req) => {
            setTimeout(() => {
                window.location.reload();
            }, 200);
            return {};
        });
        // Handler for status updates from service worker
        this.deesComms.createTypedHandler('serviceworker_statusUpdate', async (status) => {
            // Forward to all registered callbacks
            for (const callback of this.statusCallbacks) {
                try {
                    callback(status);
                }
                catch (error) {
                    logger.log('warn', `Status callback error: ${error}`);
                }
            }
            return {};
        });
    }
    /**
     * Subscribe to status updates from the service worker
     * @returns Unsubscribe function
     */
    subscribeToStatusUpdates(callback) {
        this.statusCallbacks.add(callback);
        logger.log('info', 'Subscribed to service worker status updates');
        return () => {
            this.statusCallbacks.delete(callback);
            logger.log('info', 'Unsubscribed from service worker status updates');
        };
    }
    /**
     * Get current service worker status
     */
    async getServiceWorkerStatus() {
        try {
            const tr = this.deesComms.createTypedRequest('serviceworker_getStatus');
            const response = await Promise.race([
                tr.fire({}),
                new Promise((resolve) => setTimeout(() => resolve(null), 5000)),
            ]);
            return response;
        }
        catch (error) {
            logger.log('warn', `Failed to get service worker status: ${error}`);
            return null;
        }
    }
    /**
     * Waits for service worker connection with timeout and retry logic.
     * Returns a result object instead of blocking forever.
     */
    async waitForServiceWorkerConnection(options = {}) {
        const opts = { ...DEFAULT_CONNECTION_OPTIONS, ...options };
        const startTime = Date.now();
        let attempt = 0;
        let currentDelay = opts.initialDelayMs;
        logger.log('info', 'Waiting for service worker connection...');
        const tr = this.deesComms.createTypedRequest('broadcastConnectionPolling');
        while (attempt < opts.maxRetries) {
            // Check total timeout
            const elapsed = Date.now() - startTime;
            if (elapsed >= opts.timeoutMs) {
                logger.log('warn', `Service worker connection timeout after ${elapsed}ms (${attempt} attempts)`);
                return {
                    connected: false,
                    error: 'timeout',
                    attempts: attempt,
                    duration: elapsed,
                };
            }
            attempt++;
            try {
                // Create a per-request timeout
                const requestTimeout = Math.min(currentDelay * 2, opts.maxDelayMs);
                const response = await Promise.race([
                    tr.fire({ tabId: crypto.randomUUID?.() || String(Date.now()) }),
                    new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), requestTimeout)),
                ]);
                if (response && response.serviceworkerId) {
                    const duration = Date.now() - startTime;
                    logger.log('ok', `Connected to service worker after ${attempt} attempt(s) (${duration}ms)`);
                    return {
                        connected: true,
                        attempts: attempt,
                        duration,
                    };
                }
            }
            catch (error) {
                // Request failed or timed out, continue with retry
                logger.log('note', `Connection attempt ${attempt} failed: ${error?.message || 'unknown error'}`);
            }
            // Try to wake up the service worker
            if (navigator.serviceWorker.controller) {
                try {
                    navigator.serviceWorker.controller.postMessage({
                        type: 'wakeUpCall',
                    });
                }
                catch {
                    // Ignore errors when posting message
                }
            }
            // Wait before next attempt with exponential backoff
            await plugins.smartdelay.delayFor(currentDelay);
            currentDelay = Math.min(currentDelay * opts.backoffMultiplier, opts.maxDelayMs);
        }
        const duration = Date.now() - startTime;
        logger.log('warn', `Service worker connection failed after ${opts.maxRetries} attempts (${duration}ms)`);
        return {
            connected: false,
            error: 'max_retries_exceeded',
            attempts: attempt,
            duration,
        };
    }
    /**
     * Legacy method for backward compatibility - blocks until connected or gives up
     * @deprecated Use waitForServiceWorkerConnection() instead which returns a result
     */
    async waitForServiceWorkerConnectionBlocking() {
        const result = await this.waitForServiceWorkerConnection();
        if (!result.connected) {
            logger.log('warn', `Failed to connect to service worker: ${result.error}`);
        }
    }
    async purgeServiceWorkerCache() {
        const tr = this.deesComms.createTypedRequest('purgeServiceWorkerCache');
        const response = await tr.fire({});
        return response;
    }
    async getVersionInfo() {
        const tr = this.deesComms.createTypedRequest('serviceworker_versionInfo');
        const response = await tr.fire({});
        return response;
    }
    // ================================
    // TypedRequest Traffic Logging
    // ================================
    /**
     * Log a TypedRequest entry to the service worker for dashboard display
     */
    async logTypedRequest(entry) {
        try {
            const tr = this.deesComms.createTypedRequest('serviceworker_typedRequestLog');
            tr.skipHooks = true; // Prevent infinite loops - don't log the logging request
            await tr.fire(entry);
        }
        catch (error) {
            // Silently ignore logging errors to avoid infinite loops
            // (logging the error would trigger another log entry)
        }
    }
    /**
     * Get TypedRequest traffic logs from the service worker
     */
    async getTypedRequestLogs(options) {
        try {
            const tr = this.deesComms.createTypedRequest('serviceworker_getTypedRequestLogs');
            return await tr.fire(options || {});
        }
        catch (error) {
            logger.log('warn', `Failed to get TypedRequest logs: ${error}`);
            return null;
        }
    }
    /**
     * Get TypedRequest traffic statistics from the service worker
     */
    async getTypedRequestStats() {
        try {
            const tr = this.deesComms.createTypedRequest('serviceworker_getTypedRequestStats');
            return await tr.fire({});
        }
        catch (error) {
            logger.log('warn', `Failed to get TypedRequest stats: ${error}`);
            return null;
        }
    }
    /**
     * Clear TypedRequest traffic logs
     */
    async clearTypedRequestLogs() {
        try {
            const tr = this.deesComms.createTypedRequest('serviceworker_clearTypedRequestLogs');
            const result = await tr.fire({});
            return result.success;
        }
        catch (error) {
            logger.log('warn', `Failed to clear TypedRequest logs: ${error}`);
            return false;
        }
    }
    /**
     * Subscribe to real-time TypedRequest log entries
     * @returns Unsubscribe function
     */
    subscribeToTypedRequestLogs(callback) {
        // Create handler for broadcast messages
        this.deesComms.createTypedHandler('serviceworker_typedRequestLogged', async (entry) => {
            try {
                callback(entry);
            }
            catch (error) {
                logger.log('warn', `TypedRequest log callback error: ${error}`);
            }
            return {};
        });
        logger.log('info', 'Subscribed to TypedRequest log updates');
        // Return unsubscribe function (note: DeesComms doesn't support removing handlers)
        return () => {
            logger.log('info', 'Unsubscribed from TypedRequest log updates (handler remains active)');
        };
    }
}
//# sourceMappingURL=data:application/json;base64, 