import { Logger } from '../../config/logger.js';
import { Env } from '../../config/env.js';
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
import { ZintrustLang } from '../../lang/lang.js';
import { existsSync } from '../../node-singletons/fs.js';
import * as path from '../../node-singletons/path.js';
import { pathToFileURL } from '../../node-singletons/url.js';
import { detectRuntime } from '../../runtime/detectRuntime.js';
import { DatabaseQueue } from '../queue/drivers/Database.js';
import { autoRegisterJobStateTrackerPersistenceFromEnv } from '../queue/JobStateTrackerDbPersistence.js';
import { QueueReliabilityOrchestrator } from '../queue/QueueReliabilityOrchestrator.js';
import { InMemoryQueue } from '../queue/drivers/InMemory.js';
import { Queue } from '../queue/Queue.js';
/**
 * Register queue drivers from runtime config.
 *
 * This follows the framework's config-driven availability pattern:
 * - Built-in drivers are registered so `QUEUE_DRIVER=sync|inmemory|redis` works out of the box.
 * - If the configured default is registered, it is ALSO registered as 'default'.
 * - Unknown/unregistered driver names still throw when selected.
 */
const registerRedisDriverIfAvailable = async () => {
    try {
        const mod = (await import('@zintrust/queue-redis'));
        if (mod.RedisQueue !== undefined) {
            Queue.register('redis', mod.RedisQueue);
            return true;
        }
        if (mod.BullMQRedisQueue !== undefined) {
            Queue.register('redis', mod.BullMQRedisQueue);
            return true;
        }
    }
    catch {
        // Fall back to local dist build output when running inside the core repo Docker image.
        // In that environment, `@zintrust/queue-redis` is not installed in node_modules,
        // but the compiled package is available at `dist/packages/queue-redis`.
        try {
            const cwd = typeof process !== 'undefined' && typeof process.cwd === 'function' ? process.cwd() : '';
            if (cwd.trim() === '')
                return false;
            const localEntry = path.join(cwd, 'dist', 'packages', 'queue-redis', 'src', 'index.js');
            if (!existsSync(localEntry))
                return false;
            const url = pathToFileURL(localEntry).href;
            const localMod = (await import(url));
            if (localMod.RedisQueue !== undefined) {
                Queue.register('redis', localMod.RedisQueue);
                return true;
            }
            if (localMod.BullMQRedisQueue !== undefined) {
                Queue.register('redis', localMod.BullMQRedisQueue);
                return true;
            }
        }
        catch {
            // ignore
        }
        return false;
    }
    return false;
};
export async function registerQueuesFromRuntimeConfig(config) {
    autoRegisterJobStateTrackerPersistenceFromEnv();
    // Built-in drivers (core)
    Queue.register('inmemory', InMemoryQueue);
    Queue.register(ZintrustLang.DATABASE, DatabaseQueue);
    // Project templates use QUEUE_DRIVER=sync; treat this as an alias of in-memory.
    Queue.register('sync', InMemoryQueue);
    const defaultName = (config.default ?? '').toString().trim().toLowerCase();
    if (defaultName.length === 0) {
        throw ErrorFactory.createConfigError('Queue default driver is not configured');
    }
    if (defaultName === 'redis') {
        const registered = await registerRedisDriverIfAvailable();
        if (!registered) {
            throw ErrorFactory.createConfigError('Redis queue driver is not registered. Install queue:redis via zin plugin install.');
        }
    }
    try {
        const drv = Queue.get(defaultName);
        Queue.register('default', drv);
        if (Env.getBool('JOB_RELIABILITY_AUTOSTART', false)) {
            QueueReliabilityOrchestrator.start();
        }
    }
    catch (error) {
        const { isCloudflare } = detectRuntime();
        if (isCloudflare) {
            Logger.warn(`[queue] Default driver '${defaultName}' is unavailable in Cloudflare runtime; falling back to 'sync'.`);
            Queue.register('default', Queue.get('sync'));
            return;
        }
        throw ErrorFactory.createConfigError('Queue default driver is not available', error);
    }
}
