const udpSession = require('./udp_session');
const PacketTypeEnum = require('./packet_type_enum');
const PacketQueue = require('./packet_queue');

const SendType = {
    DATAS: 1,
    RELAY: 2,
    LLM_RELAY: 3
};

const packetQueue = PacketQueue.getInstance();
let initialized = false;
let sendThread = null;

/**
 * Send a packet asynchronously
 * @param {number} packet_type - Type of packet from PacketTypeEnum
 * @param {object} ctx - Trace context
 * @param {array} datas - Array of data strings to send
 */
function send_packet(packet_type, ctx, datas = []) {
    _initThread();

    // Deep copy the context to prevent modification
    let copiedCtx = structuredClone(ctx);
    if (packetQueue.full()) {
        return;
    }

    packetQueue.put([SendType.DATAS, [packet_type, copiedCtx, datas]]);
}

/**
 * Send relay pack data asynchronously
 * @param {Buffer} packbytes - Bytes to send
 */
function send_relaypack(packbytes) {
    _initThread();

    if (packetQueue.full()) {
        return;
    }

    packetQueue.put([SendType.RELAY, packbytes]);
}

/**
 * Send LLM relay pack data to LLM Go Agent socket
 * @param {Buffer} packbytes - Bytes to send
 */
function send_llm_relaypack(packbytes) {
    _initThread();

    if (packetQueue.full()) {
        return;
    }

    packetQueue.put([SendType.LLM_RELAY, packbytes]);
}

/**
 * Start the async processing thread
 */
function startWhatapThread() {
    // If thread is already running, don't start another
    if (sendThread) {
        return;
    }

    // Start processing loop
    const processQueue = () => {
        const packet = packetQueue.get();

        if (!packet) {
            // No packet, wait and try again
            setTimeout(processQueue, 100);
            return;
        }

        try {
            const [sendType, params] = packet;
            if (sendType === SendType.DATAS) {
                const [packet_type, ctx, datas] = params;
                udpSession.send_packet(packet_type, ctx, datas);
            } else if (sendType === SendType.RELAY) {
                const packbytes = params;
                udpSession.send_relaypack(packbytes);
            } else if (sendType === SendType.LLM_RELAY) {
                const packbytes = params;
                udpSession.send_llm_relaypack(packbytes);
            }
        } catch (e) {
            console.error("Error processing queue item:", e);
        }

        // Continue processing
        setTimeout(processQueue, 0);
    };

    // Start the processing loop
    sendThread = setTimeout(processQueue, 0);
}

/**
 * Initialize the thread if not already initialized
 */
function _initThread() {
    if (initialized) {
        return;
    }

    // Lock used to avoid multiple initializations
    const initLock = function() {
        if (initialized) {
            return;
        }

        try {
            initialized = true;
            startWhatapThread();
        } catch (e) {
            console.error("Error initializing thread:", e);
            initialized = false;
        }
    };

    initLock();
}

// Export functions
module.exports = {
    send_packet,
    send_relaypack,
    send_llm_relaypack,
    startWhatapThread,
    _initThread
};