"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.queue = exports.PriorityQueue = void 0;
const uuid_1 = require("uuid");
const logger_js_1 = require("../../utils/logger.js");
const log = (0, logger_js_1.createModuleLogger)('queue-system');
// Priority mapping: lower number = higher priority
const TYPE_PRIORITY = {
    stars_payment: 1,
    chat_response: 2,
    image_generation: 3,
    quality_check: 4,
    channel_publish: 5,
    translation: 5,
};
class PriorityQueue {
    items = [];
    processing = false;
    processor = null;
    onPersist = null;
    constructor() { }
    setProcessor(processor) {
        this.processor = processor;
    }
    setOnPersist(callback) {
        this.onPersist = callback;
    }
    async add(type, characterId, payload, maxRetries = 3) {
        const item = {
            id: (0, uuid_1.v4)(),
            type,
            priority: TYPE_PRIORITY[type] || 5,
            status: 'pending',
            characterId,
            payload,
            retryCount: 0,
            maxRetries,
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
        };
        this.items.push(item);
        this.sortQueue();
        await this.persist();
        log.info({ itemId: item.id, type, priority: item.priority }, 'Task added to queue');
        // Auto-start processing if not already running
        if (!this.processing && this.processor) {
            this.processNext();
        }
        return item;
    }
    dequeue() {
        const index = this.items.findIndex(i => i.status === 'pending');
        if (index === -1)
            return undefined;
        const item = this.items[index];
        item.status = 'processing';
        item.updatedAt = new Date().toISOString();
        return item;
    }
    async updateStatus(id, status, error) {
        const item = this.items.find(i => i.id === id);
        if (!item)
            return null;
        item.status = status;
        item.updatedAt = new Date().toISOString();
        if (error)
            item.error = error;
        if (status === 'failed')
            item.retryCount++;
        await this.persist();
        return item;
    }
    getById(id) {
        return this.items.find(i => i.id === id);
    }
    getPending() {
        return this.items.filter(i => i.status === 'pending');
    }
    getFailed() {
        return this.items.filter(i => i.status === 'failed');
    }
    getAll() {
        return [...this.items];
    }
    getStats() {
        return {
            pending: this.items.filter(i => i.status === 'pending').length,
            processing: this.items.filter(i => i.status === 'processing').length,
            completed: this.items.filter(i => i.status === 'completed').length,
            failed: this.items.filter(i => i.status === 'failed').length,
        };
    }
    async retry(id) {
        const item = this.items.find(i => i.id === id && i.status === 'failed');
        if (!item)
            return false;
        if (item.retryCount >= item.maxRetries)
            return false;
        item.status = 'pending';
        item.error = undefined;
        item.updatedAt = new Date().toISOString();
        this.sortQueue();
        await this.persist();
        if (!this.processing && this.processor) {
            this.processNext();
        }
        return true;
    }
    loadItems(items) {
        this.items = items;
        this.sortQueue();
    }
    sortQueue() {
        this.items.sort((a, b) => {
            // Pending items come first
            if (a.status === 'pending' && b.status !== 'pending')
                return -1;
            if (a.status !== 'pending' && b.status === 'pending')
                return 1;
            // Then sort by priority (lower number = higher priority)
            if (a.priority !== b.priority)
                return a.priority - b.priority;
            // FIFO within same priority
            return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
        });
    }
    async processNext() {
        if (this.processing || !this.processor)
            return;
        const item = this.dequeue();
        if (!item) {
            this.processing = false;
            return;
        }
        this.processing = true;
        try {
            await this.processor(item);
            await this.updateStatus(item.id, 'completed');
        }
        catch (err) {
            log.error({ itemId: item.id, err: err.message }, 'Queue task failed');
            await this.updateStatus(item.id, 'failed', err.message);
            if (item.retryCount < item.maxRetries) {
                await this.retry(item.id);
            }
        }
        this.processing = false;
        // Process next pending item
        const nextPending = this.items.find(i => i.status === 'pending');
        if (nextPending) {
            setImmediate(() => this.processNext());
        }
    }
    async persist() {
        if (this.onPersist) {
            const pendingAndFailed = this.items.filter(i => i.status === 'pending' || i.status === 'failed' || i.status === 'processing');
            await this.onPersist(pendingAndFailed);
        }
    }
}
exports.PriorityQueue = PriorityQueue;
// Singleton instance
exports.queue = new PriorityQueue();
//# sourceMappingURL=index.js.map