const pathToFfmpeg = require('ffmpeg-static');
// const { joinVoiceChannel, createAudioResource } = require('@discordjs/voice');
const { VoiceConnectionStatus, AudioPlayerStatus, createAudioPlayer, StreamType,  joinVoiceChannel, createAudioResource, getVoiceConnection } = require('@discordjs/voice');
const { MessageActionRow, MessageButton, MessageEmbed, MessageSelectMenu, Message } = require('discord.js');
const play = require('play-dl');


// Note: Unsure of what this does , but may be related to the play-dl lib (my notes are inconsistent)
// play.authorization();

function playStopEmbed(bot, interaction, yt_info, stopped, message = null) {
    if (stopped) {
        var em = interaction.message.embeds[0];
        rows = [];
        em.description = new String;
        em.description = 'IS NOW STOPPED';
    
        interaction.update({embeds: [em], components: rows});
    } else {
        const author = {
            name: "Selmer Bot",
            url: "",
            iconURL: bot.user.displayAvatarURL()
          }
        
          const newEmbed = new MessageEmbed()
          .setColor('#0F00F0')
          .setTitle(`${yt_info.video_details.title}`)
          .setAuthor(author)
          .setDescription('IS NOW PLAYING')
          .setURL(yt_info.video_details.url)
          .setThumbnail(yt_info.video_details.thumbnails[0].url);
        
          const row = new MessageActionRow()
          .addComponents(
                new MessageButton()
                    .setCustomId('PAUSE')
                    .setLabel('⏸️')
                    .setStyle('SECONDARY'),
                new MessageButton()
                    .setCustomId('STOP')
                    .setLabel('⏹️')
                    .setStyle('SECONDARY'),
                new MessageButton()
                    .setCustomId('SKIP')
                    .setLabel('⏭️')
                    .setStyle('SECONDARY')
          );
        

          if (message) {
            const m = message.reply({ embeds: [newEmbed], components: [row] });
            m.then((msg) => {
                const data = bot.audioData.get(message.guild.id);
                data[2] = msg.id;
                bot.audioData.set(message.guild.id, data);
            })
          } else {
            interaction.update({embeds: [newEmbed], components: [row]});
          }
    }
}


function pause_start_stop(interaction, bot, message = null, command = null) {
    try {
        var player, em;

        if (interaction) {
            player = bot.audioData.get(interaction.guildId)[0];
            command = interaction.customId.toLowerCase();
            em = interaction.message.embeds[0];
        } else {
            player = bot.audioData.get(message.guild.id)[0];
            em = message.embeds[0];
        }
        
        var rows = [new MessageActionRow()];

        if (command == "pause") {
            rows[0].addComponents(
                new MessageButton()
                    .setCustomId('RESUME')
                    .setLabel('▶️')
                    .setStyle('SECONDARY'),
                new MessageButton()
                    .setCustomId('STOP')
                    .setLabel('⏹️')
                    .setStyle('SECONDARY'),
                new MessageButton()
                    .setCustomId('SKIP')
                    .setLabel('⏭️')
                    .setStyle('SECONDARY')
            );
            
            em.description = 'IS NOW PAUSED';
            player.pause();

        } else if (command == "resume") {
            rows[0].addComponents(
                new MessageButton()
                    .setCustomId('PAUSE')
                    .setLabel('⏸️')
                    .setStyle('SECONDARY'),
                new MessageButton()
                    .setCustomId('STOP')
                    .setLabel('⏹️')
                    .setStyle('SECONDARY'),
                new MessageButton()
                    .setCustomId('SKIP')
                    .setLabel('⏭️')
                    .setStyle('SECONDARY')
            );
            
            em.description = 'IS NOW PLAYING';

            player.unpause();
        } else if (command == "stop") {
            playStopEmbed(bot, interaction, null, true);

            const connection = getVoiceConnection(interaction.guild.id);
            
            player.stop();

            //Remove everything from queue
            bot.audioData.delete(interaction.guildId);

            if (connection) { connection.destroy(); }
            return;
        }

        if (interaction) { interaction.update({embeds: [em], components: rows}); }
        else {
            const data = bot.audioData.get(message.guild.id);
            
            // var msg = message.channel.messages.cache.get(data[2]);
            const newEmbed = message.embeds[0];
            newEmbed.description = "Has been deferred";
            message.edit({ embeds: [ newEmbed ], components: []});

            const m = message.reply({embeds: [em], components: rows});
            m.then((msg) => {
                const data = bot.audioData.get(message.guild.id);
                data[2] = msg.id;
                bot.audioData.set(message.guild.id, data);
            })
        }
        
    } catch (e) {
        console.log(e);
        rows = [];
        em.description = new String('IS NOW STOPPED');
        interaction.update({embeds: [em], components: rows});
    }
}


function playNext(interaction, bot, message = null) {
    // https://discordjs.guide/voice/audio-player.html#taking-action-within-the-error-handler

    //Setup data[1] = {info: yt_info, resource: resource}
    var guildId;
    if (message != null) { guildId = message.guild.id; }
    else { guildId = interaction.guildId; }

    let data = bot.audioData.get(guildId);
    const player = data[0];

    //Check if the queue is empty
    if (data[1].length <= 0) { 
        player.stop();
        bot.audioData.delete(guildId);
        if (message) { return true; }
        else { return playStopEmbed(bot, interaction, null, true); }
    }
    

    const resource = data[1][0].resource;
    const yt_info = data[1][0].yt_info;
    player.stop();

    //Play the thing
    player.play(resource);

    //remove the song from queue
    delete data[1][0];
    data[1] = data[1].filter(n => n);

    bot.audioData.set(guildId, data);

    //Add the embed
    var msg = message;
    if (!message) {
        msg = interaction.message;
        interaction.update({ embeds: [ new MessageEmbed(interaction.message.embeds[0]).setDescription("IS NOW STOPPED") ], components: []});
    }

    playStopEmbed(bot, interaction, yt_info, false, msg);

    return false;
}


function fromMessage(bot, command, msg) {
    //Setup data[1] = {info: yt_info, resource: resource}
    const guildId = msg.guild.id;
    let data = bot.audioData.get(guildId);
    if (!data) { return msg.reply("No music is currently playing!"); }

    const player = data[0];
    const message = msg.channel.messages.cache.get(data[2]);
    // console.log(message);

    var em = message.embeds[0];
    var rows;

    if (command == 'stop') {
        em = message.embeds[0];
        rows = [];
        em.description = new String;
        em.description = 'IS NOW STOPPED';
        
        player.stop();
        const connection = getVoiceConnection(guildId);
        if (connection) { connection.destroy(); }

        bot.audioData.delete(guildId);
        msg.reply("Audio stopped!");
        
    } else if (command == 'skip') {
        if (playNext(null, bot, message)) {
            rows = [];
            em = message.embeds[0];
            em.description = new String;
            em.description = 'IS NOW STOPPED';

            msg.reply("Audio stopped!");
        }
    } else if (command == 'pause' || command == 'resume') {
        pause_start_stop(null, bot, message, command);
    }


    message.edit({embeds: [em], components: rows});
}



function showQueue(bot, message, interaction = null, page = 0) {
    const guild = message.guild.id;
    const data = bot.audioData.get(guild);
    if (!data) { return message.reply("The audio queue is empty!"); }

    const rawQueue = data[1];
    if (!rawQueue || rawQueue.length <= 0) { return message.reply("The audio queue is empty!"); }

    const songList = [];
    var fiveSongs = '';
    let i = 0;

    rawQueue.forEach(function (rawSong) {
        const songDetails = rawSong.yt_info.video_details;
        fiveSongs += `${i + 1}. ${songDetails.title}\n`;

        i++;

        //Split the songs into pages of 10
        if (i % 10 == 0) { songList.push(fiveSongs); fiveSongs = ''; }
    });

    if (page >= songList.length) { page = songList.length - 1 }
    if (page < 0) { page = 0; } //LEAVE AS TWO IF's AS THE LENGTH MIGHT BE 0

    if (songList.length == 0) { songList.push(fiveSongs); }

    //Create the embed
    const author = {
        name: "Selmer Bot",
        url: "",
        iconURL: bot.user.displayAvatarURL()
    }
    
    const newEmbed = new MessageEmbed()
    .setTitle("SONG QUEUE")
    .setAuthor(author)
    .setDescription(songList[page])
    .setFooter({ text: `Page ${page + 1}` })

    const row = new MessageActionRow()
    .addComponents(
        new MessageButton()
            .setCustomId(`audioQueue|${page - 1}`)
            .setLabel('⬅️')
            .setStyle('SECONDARY'),
        new MessageButton()
            .setCustomId(`audioQueue|${page + 1}`)
            .setLabel('➡️')
            .setStyle('SECONDARY'),
        
    )

    if (interaction) {
        interaction.update({embeds: [newEmbed], components: [row]});
    } else {
        message.reply({ embeds: [newEmbed], components: [row] });
    }
}


function removeFromQueue(bot, message, posStr) {
    const guildId = message.guild.id;
    let data = bot.audioData.get(guildId);
    if (!data) { return message.reply("The audio queue is empty!"); }

    const rawQueue = data[1];
    if (!rawQueue || rawQueue.length <= 0) { return message.reply("The audio queue is empty!"); }
    else if (isNaN(posStr) || Number(posStr) > rawQueue.length) { return message.reply("Please specify a number within queue bounds!"); }

    const pos = Number(posStr) - 1;
    const details = rawQueue[pos].yt_info.video_details;

    delete data[1][pos];
    data[1] = data[1].filter(n => n);
    
    bot.audioData.set(guildId, data);

    const newEmbed = new MessageEmbed()
    .setColor('#0F00F0')
    .setTitle(`${details.title}`)
    .setAuthor({ name: "Selmer Bot", url: "", iconURL: bot.user.displayAvatarURL() })
    .setDescription( `has been removed from position ${pos + 1} in queue!`)
    .setThumbnail(details.thumbnails[0].url);

    message.reply({ embeds: [newEmbed] });
}



function shuffleQueue(bot, message) {
    const guildId = message.guild.id;
    let data = bot.audioData.get(guildId);
    if (!data) { return message.reply("The audio queue is empty!"); }

    let rawQueue = data[1];
    if (!rawQueue || rawQueue.length <= 0) { return message.reply("The audio queue is empty!"); }

    //Shuffle the queue
    rawQueue = rawQueue.sort(() => Math.random()-0.5);

    data[1] = rawQueue;

    bot.audioData.set(guildId, data);

    message.reply("The queue has been shuffled!\nThe new queue is:");
    showQueue(bot, message);
}



module.exports = {
    name: "audio",
    description: 'Play a song from YouTube, add free!',
    async execute(message, args, Discord, Client, bot, interaction = null) {
            const commandList = ['stop', 'skip', 'pause', 'resume'];

            if (args.length < 1) {
                message.reply("Please use the following format _!audio [song name or URL]_ **or** _!audio queue_");
                return;
            } else if (args[0] == 'queue') {
                return showQueue(bot, message);
            } else if (commandList.indexOf(args[0]) != -1) {
                return fromMessage(bot, args[0], message);
            } else if (args[0] == 'remove') {
                if (args.length < 2) { return message.reply("Please specify a position in queue!"); }
                return removeFromQueue(bot, message, args[1]);
            } else if (args[0] == 'shuffle') {
                return shuffleQueue(bot, message);
            }

            /*
            Re-introduce once the issue with ydtl-core is resolved (see
            https://github.com/porridgewithraisins/jam-bot#known-bugs)
            const stream = await ytdl(url, { filter: 'audioonly' });
            */
           
            if (!message.member.voice.channel) {
                message.reply("Please join a voice channel before you try this!");
                return;
            }

            const channel =  bot.channels.cache.get(message.member.voice.channel.id);
            // console.log(message.member.voice.channel.id);

            const connection = joinVoiceChannel({
                channelId: channel.id,
                guildId: channel.guild.id,
                adapterCreator: channel.guild.voiceAdapterCreator,
            });

            connection.on(VoiceConnectionStatus.Ready, () => {
                // console.log('Connected to the voice channel!');
            });
        
            let stream;
            let yt_info;
            if (args[0].startsWith("https://")) {
                if (!args[0].startsWith("https://www.youtube.com/") &&
                !args[0].startsWith("https://music.youtube.com/")) {
                    message.reply("This is not a valid YouTube URL");
                    return;
                }
                yt_info = await play.video_info(args[0]);
                // let stream = await play.stream_from_info(yt_info)
                stream = await play.stream(args[0]);

                // console.log("Playing from a URL!");
            } else {
                yt_info = await play.search(args.join(' '), {
                    limit: 1
                });

                stream = await play.stream(yt_info[0].url);
                yt_info = await play.video_info(yt_info[0].url);
            }

            let resource = createAudioResource(stream.stream, {
                inputType: stream.type
            })

            // let audio = "em.mp3";
            // let resource = createAudioResource(join(__dirname, audio));
            
            const data = bot.audioData.get(channel.guild.id);

            if (data && data[1]) {
                //[player, [queue Array]]
                data[1].push({yt_info: yt_info, resource: resource});
                bot.audioData.set(message.guild.id, data);
                message.reply(`_"${yt_info.video_details.title}" added to queue!_`);
            } else {
                const player = createAudioPlayer();
                connection.subscribe(player);

                bot.audioData.set(message.guild.id, [player, new Array(), null]);
                player.play(resource);


                player.on(AudioPlayerStatus.Playing, () => {
                    //Check maybe?
                });

                playStopEmbed(bot, interaction, yt_info, false, message);
            }

            

    }, pause_start_stop, playNext, showQueue
}