import { irohTransport } from './iroh-transport.js';
import { p2pNetwork } from './p2p.js';
const DEFAULT_CONFIG = {
    preferIrohForLarge: true,
    largeThresholdBytes: 64 * 1024,
    enableRelay: true,
};
export class HybridMessenger {
    messageHandlers = new Map();
    wildcardHandler = null;
    config;
    irohEnabled = true;
    constructor(config = {}) {
        this.config = { ...DEFAULT_CONFIG, ...config };
    }
    selectTransport(type, payloadSize, priority = 'normal') {
        if (this.irohEnabled && this.shouldUseIroh(type, payloadSize, priority)) {
            return 'iroh';
        }
        if (priority === 'urgent' || type === 'relay') {
            return 'libp2p';
        }
        return 'hyperswarm';
    }
    shouldUseIroh(type, payloadSize, priority) {
        const bulkTypes = ['blob', 'stream', 'file', 'large-data'];
        if (bulkTypes.includes(type) || payloadSize > this.config.largeThresholdBytes) {
            return true;
        }
        if (priority === 'bulk' && payloadSize > 1024) {
            return true;
        }
        return false;
    }
    async sendMessage(targetId, type, payload, options = {}) {
        const { priority = 'normal', preferTransport, relayAddr } = options;
        const payloadBytes = typeof payload === 'string'
            ? new TextEncoder().encode(payload)
            : payload;
        const transport = preferTransport || this.selectTransport(type, payloadBytes.length, priority);
        console.log(`[HybridMessenger] Sending "${type}" (${payloadBytes.length} bytes) via ${transport}`);
        switch (transport) {
            case 'iroh':
                return this.sendViaIroh(targetId, type, payloadBytes);
            case 'libp2p':
                return this.sendViaLibp2p(targetId, type, payloadBytes, relayAddr);
            case 'hyperswarm':
            default:
                return this.sendViaHyperswarm(targetId, type, payloadBytes);
        }
    }
    async sendViaIroh(targetId, type, payload) {
        try {
            return await irohTransport.sendMessage(targetId, type, payload);
        }
        catch (e) {
            console.warn('[HybridMessenger] iroh send failed:', e);
            return false;
        }
    }
    async sendViaLibp2p(targetId, type, payload, relayAddr) {
        try {
            await p2pNetwork.sendMessage(targetId, type, new TextDecoder().decode(payload));
            return true;
        }
        catch (e) {
            console.warn('[HybridMessenger] libp2p send failed:', e);
            return false;
        }
    }
    async sendViaHyperswarm(targetId, type, payload) {
        try {
            await p2pNetwork.sendMessage(targetId, type, new TextDecoder().decode(payload));
            return true;
        }
        catch (e) {
            console.warn('[HybridMessenger] Hyperswarm send failed:', e);
            return false;
        }
    }
    async broadcast(type, payload, options = {}) {
        const { priority = 'normal', transport } = options;
        const payloadBytes = typeof payload === 'string'
            ? new TextEncoder().encode(payload)
            : payload;
        const selectedTransport = transport || this.selectTransport(type, payloadBytes.length, priority);
        if (selectedTransport === 'iroh') {
            await irohTransport.broadcast(type, payloadBytes);
        }
        else {
            await p2pNetwork.broadcast(type, new TextDecoder().decode(payloadBytes));
        }
    }
    onMessage(type, handler) {
        this.messageHandlers.set(type, handler);
    }
    onWildcard(handler) {
        this.wildcardHandler = handler;
    }
    dispatchMessage(msg) {
        const handler = this.messageHandlers.get(msg.type);
        if (handler) {
            handler(msg);
        }
        else if (this.wildcardHandler) {
            this.wildcardHandler(msg);
        }
    }
    setIrohEnabled(enabled) {
        this.irohEnabled = enabled;
    }
    isIrohEnabled() {
        return this.irohEnabled;
    }
    getConfig() {
        return { ...this.config };
    }
    setLargeThreshold(bytes) {
        this.config.largeThresholdBytes = bytes;
    }
    setPreferIrohForLarge(enabled) {
        this.config.preferIrohForLarge = enabled;
    }
}
export const hybridMessenger = new HybridMessenger();
