import { QueueError } from './optimisticErrors.js';

/**
 * Action Queue for Offline Support
 * Manages queued mutations when the user is offline
 */
/**
 * ActionQueue class for managing offline mutations
 */
class ActionQueue {
    constructor(options = {}) {
        var _a, _b, _c;
        this.queue = [];
        this.isProcessing = false;
        this.options = {
            maxRetries: (_a = options.maxRetries) !== null && _a !== void 0 ? _a : 3,
            storageKey: (_b = options.storageKey) !== null && _b !== void 0 ? _b : "flikkui-action-queue",
            persist: (_c = options.persist) !== null && _c !== void 0 ? _c : true,
            onActionSuccess: options.onActionSuccess,
            onActionFailed: options.onActionFailed,
            onQueueChange: options.onQueueChange,
        };
        // Load persisted queue on initialization
        if (this.options.persist) {
            this.loadFromStorage();
        }
    }
    /**
     * Generate a unique ID for an action
     */
    generateId() {
        return `action-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
    }
    /**
     * Save queue to localStorage
     */
    saveToStorage() {
        if (!this.options.persist || typeof window === "undefined")
            return;
        try {
            // We can't serialize functions, so we only persist metadata
            const persistableQueue = this.queue.map(({ id, timestamp, retryCount, maxRetries, metadata }) => ({
                id,
                timestamp,
                retryCount,
                maxRetries,
                metadata,
            }));
            localStorage.setItem(this.options.storageKey, JSON.stringify(persistableQueue));
        }
        catch (_a) {
            // localStorage might be unavailable or full
            if (process.env.NODE_ENV !== "production") {
                console.warn("[ActionQueue] Failed to persist queue to localStorage");
            }
        }
    }
    /**
     * Load queue from localStorage
     * Note: Actions (functions) cannot be persisted, only metadata
     */
    loadFromStorage() {
        if (typeof window === "undefined")
            return;
        try {
            const stored = localStorage.getItem(this.options.storageKey);
            if (stored) {
                // Only load metadata - actions will need to be re-registered
                const parsed = JSON.parse(stored);
                if (process.env.NODE_ENV !== "production" && parsed.length > 0) {
                    console.warn(`[ActionQueue] Found ${parsed.length} stale queued actions. Actions cannot be restored after page reload.`);
                }
                // Clear stale entries
                localStorage.removeItem(this.options.storageKey);
            }
        }
        catch (_a) {
            // localStorage might be unavailable
        }
    }
    /**
     * Notify listeners of queue changes
     */
    notifyChange() {
        var _a, _b;
        this.saveToStorage();
        (_b = (_a = this.options).onQueueChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.queue);
    }
    /**
     * Add an action to the queue
     * @returns The action ID
     */
    add(action, options) {
        var _a;
        const id = this.generateId();
        const queuedAction = {
            id,
            action,
            timestamp: Date.now(),
            retryCount: 0,
            maxRetries: (_a = options === null || options === void 0 ? void 0 : options.maxRetries) !== null && _a !== void 0 ? _a : this.options.maxRetries,
            metadata: {
                label: options === null || options === void 0 ? void 0 : options.label,
                description: options === null || options === void 0 ? void 0 : options.description,
            },
        };
        this.queue.push(queuedAction);
        this.notifyChange();
        return id;
    }
    /**
     * Remove an action from the queue
     */
    remove(id) {
        const initialLength = this.queue.length;
        this.queue = this.queue.filter((action) => action.id !== id);
        if (this.queue.length !== initialLength) {
            this.notifyChange();
            return true;
        }
        return false;
    }
    /**
     * Get all queued actions
     */
    getAll() {
        return [...this.queue];
    }
    /**
     * Get the number of queued actions
     */
    get size() {
        return this.queue.length;
    }
    /**
     * Check if queue is currently processing
     */
    get processing() {
        return this.isProcessing;
    }
    /**
     * Clear all queued actions
     */
    clear() {
        this.queue = [];
        this.notifyChange();
    }
    /**
     * Process all queued actions
     * Call this when the user comes back online
     */
    async process() {
        var _a, _b, _c, _d;
        if (this.isProcessing || this.queue.length === 0)
            return;
        this.isProcessing = true;
        // Process actions in order
        while (this.queue.length > 0) {
            const action = this.queue[0];
            try {
                const result = await action.action();
                (_b = (_a = this.options).onActionSuccess) === null || _b === void 0 ? void 0 : _b.call(_a, action, result);
                this.queue.shift(); // Remove successful action
                this.notifyChange();
            }
            catch (error) {
                action.retryCount++;
                if (action.retryCount >= action.maxRetries) {
                    // Max retries reached, remove and report failure
                    (_d = (_c = this.options).onActionFailed) === null || _d === void 0 ? void 0 : _d.call(_c, action, error instanceof Error
                        ? error
                        : new QueueError("Action failed after max retries", action.id, error));
                    this.queue.shift();
                    this.notifyChange();
                }
                else {
                    // Will retry on next process() call
                    this.notifyChange();
                    break; // Stop processing, wait for next attempt
                }
            }
        }
        this.isProcessing = false;
    }
}
/**
 * Create an ActionQueue instance
 */
const createActionQueue = (options) => {
    return new ActionQueue(options);
};
/**
 * Default singleton queue for simple use cases
 */
let defaultQueue = null;
const getDefaultQueue = () => {
    if (!defaultQueue) {
        defaultQueue = createActionQueue();
    }
    return defaultQueue;
};

export { ActionQueue, createActionQueue, getDefaultQueue };
