import { InMemoryDriver } from './drivers/InMemory.js';
import { PusherDriver } from './drivers/Pusher.js';
import { RedisDriver } from './drivers/Redis.js';
import { RedisHttpsDriver } from './drivers/RedisHttps.js';
import broadcastConfig from '../../config/broadcast.js';
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
const resolveBroadcasterConfig = async (name) => {
    const selection = (name ?? broadcastConfig.getDriverName()).toString().trim().toLowerCase();
    try {
        const { BroadcastRegistry } = await import('./BroadcastRegistry.js');
        if (BroadcastRegistry.has(selection)) {
            return BroadcastRegistry.get(selection);
        }
        try {
            const { registerBroadcastersFromRuntimeConfig } = await import('./BroadcastRuntimeRegistration.js');
            registerBroadcastersFromRuntimeConfig(broadcastConfig);
        }
        catch {
            // best-effort
        }
        if (BroadcastRegistry.has(selection)) {
            return BroadcastRegistry.get(selection);
        }
    }
    catch {
        // best-effort
    }
    // Fallback to config lookup (throws on explicit unknown).
    return broadcastConfig.getDriverConfig(name);
};
const sendWithConfig = async (config, channel, event, data) => {
    const driverName = config.driver;
    if (driverName === 'inmemory') {
        return InMemoryDriver.send(undefined, channel, event, data);
    }
    if (driverName === 'pusher') {
        return PusherDriver.send(config, channel, event, data);
    }
    if (driverName === 'redis') {
        return RedisDriver.send(config, channel, event, data);
    }
    if (driverName === 'redishttps') {
        return RedisHttpsDriver.send(config, channel, event, data);
    }
    throw ErrorFactory.createConfigError(`Broadcast driver not implemented: ${driverName}`);
};
export const Broadcast = Object.freeze({
    async send(channel, event, data) {
        const config = await resolveBroadcasterConfig();
        return sendWithConfig(config, channel, event, data);
    },
    // Alias for send() - explicit intent for immediate broadcast
    async broadcastNow(channel, event, data) {
        return this.send(channel, event, data);
    },
    // Queue broadcast for async processing
    async BroadcastLater(channel, event, data, options = {}) {
        const { queueName = 'broadcasts', timestamp = Date.now() } = options;
        const { Queue } = await import('../queue/Queue.js');
        const messageId = await Queue.enqueue(queueName, {
            type: 'broadcast',
            channel,
            event,
            data,
            timestamp,
            attempts: 0,
        });
        return messageId;
    },
    queue(queueName) {
        return Object.freeze({
            BroadcastLater: async (channel, event, data, options = {}) => Broadcast.BroadcastLater(channel, event, data, { ...options, queueName }),
        });
    },
    broadcaster(name) {
        return Object.freeze({
            send: async (channel, event, data) => {
                const config = await resolveBroadcasterConfig(name);
                return sendWithConfig(config, channel, event, data);
            },
        });
    },
});
export default Broadcast;
