import { Queue, Worker, QueueEvents } from 'bullmq';
import { getRedisClient } from '../db/redis.js';
import { queueConfig } from './config.js';
import { createLogger } from '@4runr/shared';
import { processRunExecutionJob } from './processor.js';
const logger = createLogger('Gateway:Queue');
let runExecutionQueue = null;
let runExecutionWorker = null;
let runExecutionQueueEvents = null;
export async function initializeQueue() {
    if (runExecutionQueue) {
        return runExecutionQueue;
    }
    const redis = await getRedisClient();
    if (!redis) {
        logger.warn('Redis not available, queue system disabled');
        return null;
    }
    try {
        runExecutionQueue = new Queue(queueConfig.name, {
            connection: redis,
            defaultJobOptions: {
                attempts: queueConfig.attempts,
                backoff: queueConfig.backoff,
                removeOnComplete: queueConfig.removeOnComplete,
                removeOnFail: queueConfig.removeOnFail,
            },
        });
        runExecutionWorker = new Worker(queueConfig.name, async (job) => {
            return await processRunExecutionJob(job);
        }, {
            connection: redis,
            concurrency: 10,
            removeOnComplete: queueConfig.removeOnComplete,
            removeOnFail: queueConfig.removeOnFail,
        });
        runExecutionWorker.on('completed', (job) => {
            logger.info('Job completed', {
                jobId: job.id,
                runId: job.data.runId
            });
        });
        runExecutionWorker.on('failed', (job, err) => {
            logger.error('Job failed', {
                jobId: job?.id,
                runId: job?.data.runId,
                error: err.message,
                attemptsMade: job?.attemptsMade,
            });
        });
        runExecutionWorker.on('active', (job) => {
            logger.debug('Job active', {
                jobId: job.id,
                runId: job.data.runId
            });
        });
        runExecutionWorker.on('error', (err) => {
            logger.error('Worker error', { error: err.message });
        });
        runExecutionQueueEvents = new QueueEvents(queueConfig.name, {
            connection: redis,
        });
        runExecutionQueueEvents.on('waiting', ({ jobId }) => {
            logger.debug('Job waiting', { jobId });
        });
        runExecutionQueueEvents.on('active', ({ jobId }) => {
            logger.debug('Job active', { jobId });
        });
        runExecutionQueueEvents.on('completed', ({ jobId }) => {
            logger.debug('Job completed', { jobId });
        });
        runExecutionQueueEvents.on('failed', ({ jobId, failedReason }) => {
            logger.warn('Job failed', { jobId, failedReason });
        });
        logger.info('Queue system initialized', {
            queueName: queueConfig.name,
            concurrency: 10,
        });
        return runExecutionQueue;
    }
    catch (error) {
        logger.error('Failed to initialize queue', {
            error: error instanceof Error ? error.message : String(error),
        });
        return null;
    }
}
export function getQueue() {
    return runExecutionQueue;
}
export async function queueRunExecution(runId, priority = 'normal') {
    const queue = getQueue();
    if (!queue) {
        logger.warn('Queue not available, cannot queue run execution', { runId });
        throw new Error('Queue system not available');
    }
    const jobData = {
        runId,
        priority,
    };
    const priorityValue = queueConfig.priorities[priority];
    await queue.add('run-execution', jobData, {
        priority: priorityValue,
        jobId: `run-${runId}`,
    });
    logger.info('Run execution queued', { runId, priority });
}
export async function removeRunExecutionJob(runId) {
    const queue = getQueue();
    if (!queue) {
        return;
    }
    const job = await queue.getJob(`run-${runId}`);
    if (job) {
        await job.remove();
        logger.info('Run execution job removed', { runId });
    }
}
export async function getRunJobStatus(runId) {
    const queue = getQueue();
    if (!queue) {
        return null;
    }
    const job = await queue.getJob(`run-${runId}`);
    if (!job) {
        return null;
    }
    const state = await job.getState();
    const progress = typeof job.progress === 'number' ? job.progress : undefined;
    return {
        state: state,
        ...(progress !== undefined && { progress }),
        attemptsMade: job.attemptsMade,
    };
}
export async function shutdownQueue() {
    logger.info('Shutting down queue system');
    if (runExecutionWorker) {
        await runExecutionWorker.close();
        runExecutionWorker = null;
    }
    if (runExecutionQueueEvents) {
        await runExecutionQueueEvents.close();
        runExecutionQueueEvents = null;
    }
    if (runExecutionQueue) {
        await runExecutionQueue.close();
        runExecutionQueue = null;
    }
    logger.info('Queue system shut down');
}
//# sourceMappingURL=index.js.map