import { Buffer } from 'node:buffer';
import { PassThrough } from 'node:stream';
import { VoiceConnectionStatus } from '@discordjs/voice';
import * as prism from 'prism-media';
import { Resampler } from '@purinton/resampler';
// Discord expects Opus packets every 20ms
const FRAME_LENGTH = 20;
export function createDirectVoiceStreamer({ connection, inputSampleRate, inputChannels, onStop, }) {
    let active = true;
    const opusChannels = 2;
    // Create resampler to convert input to 48kHz stereo (Discord's format)
    const resampler = new Resampler({
        inRate: inputSampleRate,
        outRate: 48000,
        inChannels: inputChannels,
        volume: 1,
        filterWindow: 8,
        outChannels: opusChannels,
    });
    resampler.on('error', (error) => {
        console.error('[DIRECT VOICE] Resampler error:', error);
    });
    resampler.on('end', () => {
        console.error('[DIRECT VOICE] Resampler end');
    });
    const frameSize = 48000 * 20 / 1000; // 20ms at 48kHz = 960 samples per frame
    // Create Opus encoder for Discord (48kHz stereo)
    const encoder = new prism.opus.Encoder({
        rate: 48000,
        channels: opusChannels,
        frameSize,
    });
    // Pipe resampler to encoder
    resampler.pipe(encoder);
    let packetInterval = null;
    const opusPacketQueue = [];
    encoder.on('data', (packet) => {
        // Opus encoder outputs complete packets, don't buffer them
        opusPacketQueue.push(packet);
    });
    // Send packets at 20ms intervals as Discord expects
    packetInterval = setInterval(() => {
        if (!active) {
            if (packetInterval) {
                clearInterval(packetInterval);
                packetInterval = null;
            }
            return;
        }
        const packet = opusPacketQueue.shift();
        if (!packet)
            return;
        if (connection.state.status !== VoiceConnectionStatus.Ready) {
            console.log('[DIRECT VOICE] Skipping packet: connection not ready');
            return;
        }
        try {
            connection.setSpeaking(true);
            connection.playOpusPacket(packet);
            console.log('[DIRECT VOICE] Sent Opus packet of size', packet.length);
        }
        catch (error) {
            console.error('[DIRECT VOICE] Error sending packet:', error);
        }
    }, 20); // 20ms interval
    encoder.on('error', (error) => {
        console.error('[DIRECT VOICE] Encoder error:', error);
    });
    return {
        write(pcmData) {
            if (!active) {
                throw new Error('Voice streamer has been stopped');
            }
            resampler.write(pcmData);
        },
        interrupt() {
            // Clear the Opus packet queue
            opusPacketQueue.length = 0;
            // Stop speaking immediately
            connection.setSpeaking(false);
            console.log('[DIRECT VOICE] Interrupted - cleared queue');
        },
        stop() {
            if (!active)
                return;
            active = false;
            // Stop speaking
            connection.setSpeaking(false);
            // Clear the packet interval
            if (packetInterval) {
                clearInterval(packetInterval);
                packetInterval = null;
            }
            // Close the resampler input
            resampler.end();
            onStop?.();
        },
        get isActive() {
            return active;
        },
    };
}
