const { spawn } = require('child_process');
const { serverConfig } = require('../server_config');
const { logDebug, logError, logInfo, logWarn, logFfmpeg } = require('../console');
const checkFFmpeg = require('./checkFFmpeg');
const { PassThrough } = require('stream');

const consoleLogTitle = '[Audio Stream]';

let startupSuccess;

function connectMessage(message) {
    if (!startupSuccess) {
        logInfo(message);
        startupSuccess = true;
    }
}

const audio_pipe = new PassThrough();

checkFFmpeg().then((ffmpegPath) => {
    logInfo(`${consoleLogTitle} Using ${ffmpegPath === 'ffmpeg' ? 'system-installed FFmpeg' : 'ffmpeg-static'}`);
    logInfo(`${consoleLogTitle} Starting audio stream on device: \x1b[35m${serverConfig.audio.audioDevice}\x1b[0m`);

    const sampleRate =
        Number(this?.Server?.SampleRate || serverConfig.audio.sampleRate || 44100) +
        Number(serverConfig.audio.samplerateOffset || 0);

    const channels =
        Number(this?.Server?.Channels || serverConfig.audio.audioChannels || 2);

    let ffmpeg = null;
    let restartTimer = null;
    let lastTimestamp = null;
    let staleCount = 0;
    let lastCheckTime = Date.now();

    function buildArgs() {
        const device = serverConfig.audio.audioDevice;

        let inputArgs;

        if (process.platform === 'win32') {
            inputArgs = ["-f", "dshow", "-i", `audio=${device}`];
        } else if (process.platform === 'darwin') {
            inputArgs = ["-f", "avfoundation", "-i", device || ":0"];
        } else {
            inputArgs = ["-f", "alsa", "-i", device];
        }

        return [
            "-fflags", "+nobuffer",
            "-flags", "low_delay",
            "-rtbufsize", "4096",
            "-probesize", "128",

            ...inputArgs,

            "-ar", String(sampleRate),
            "-ac", String(channels),

            "-c:a", "libmp3lame",
            "-b:a", serverConfig.audio.audioBitrate,
            "-ac", String(channels),
            "-reservoir", "0",

            "-f", "mp3",
            "-write_xing", "0",
            "-id3v2_version", "0",

            "-fflags", "+nobuffer",
            "-flush_packets", "1",

            "pipe:1"
        ];
    }

    function launchFFmpeg() {
        const args = buildArgs();

        logDebug(`${consoleLogTitle} Launching FFmpeg with args: ${args.join(' ')}`);

        ffmpeg = spawn(ffmpegPath, args, {
            stdio: ['ignore', 'pipe', 'pipe']
        });

        ffmpeg.stdout.pipe(audio_pipe, { end: false });

        connectMessage(
            `${consoleLogTitle} Connected FFmpeg → MP3 → Server.StdIn`
        );

        ffmpeg.stderr.on('data', (data) => {
            const msg = data.toString();
            logFfmpeg(`[FFmpeg stderr]: ${msg}`);

            // Detect frozen timestamps
            const match = msg.match(/time=(\d\d):(\d\d):(\d\d\.\d+)/);
            if (match) {
                const [_, hh, mm, ss] = match;
                const totalSec =
                    parseInt(hh) * 3600 +
                    parseInt(mm) * 60 +
                    parseFloat(ss);

                if (lastTimestamp !== null && totalSec === lastTimestamp) {
                    staleCount++;
                    const now = Date.now();

                    if (staleCount >= 10 && now - lastCheckTime > 10000 && !restartTimer) {
                        logWarn(`${consoleLogTitle} FFmpeg appears frozen. Restarting...`);

                        restartTimer = setTimeout(() => {
                            restartTimer = null;
                            staleCount = 0;
                            try {
                                ffmpeg.kill('SIGKILL');
                            } catch (e) {
                                logWarn(`${consoleLogTitle} Failed to kill FFmpeg: ${e.message}`);
                            }
                            launchFFmpeg();
                        }, 0);
                    }
                } else {
                    lastTimestamp = totalSec;
                    lastCheckTime = Date.now();
                    staleCount = 0;
                }
            }
        });

        ffmpeg.on('exit', (code, signal) => {
            if (signal) {
                logWarn(`${consoleLogTitle} FFmpeg killed with signal ${signal}`);
            } else if (code !== 0) {
                logWarn(`${consoleLogTitle} FFmpeg exited with code ${code}`);
            }

            logWarn(`${consoleLogTitle} Restarting FFmpeg in 5 seconds...`);
            setTimeout(launchFFmpeg, 5000);
        });
    }

    process.on('SIGINT', () => {
        if (ffmpeg) ffmpeg.kill('SIGINT');
        process.exit();
    });

    process.on('exit', () => {
        if (ffmpeg) ffmpeg.kill('SIGINT');
    });

    launchFFmpeg();

}).catch((err) => {
    logError(`${consoleLogTitle} Error: ${err.message}`);
});

module.exports.audio_pipe = audio_pipe;