const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags, AttachmentBuilder } = require('discord.js')
const { mClient } = require('../../../index')
require('dotenv').config()

function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }

const asset_path = './assets/Command_Nuts/'

async function nutsGive(interaction) {
    async function tradeWindow(buttonID1, buttonID2) {
        const embed = new EmbedBuilder()
            .setTitle('Gib Nuss!')
            .setDescription(`Willst du wirklich **${amount}** Nüsse an <@${to.id}> senden?`)
            .addFields(
                { name: `Your Current Balance`, value: `${yourBalance.nuts} (**-${amount}**)`, inline: true },
                { name: `Your New Balance`, value: `${yourBalance.nuts - amount}`, inline: true },
                { name: '\u200B', value: '\u200B' },
                { name: `Their Current Balance`, value: `${theirBalance.nuts} (**+${amount}**)`, inline: true },
                { name: `Their New Balance`, value: `${theirBalance.nuts + amount}`, inline: true }
            )
            .setThumbnail('attachment://nuts_main.png')

        const row = new ActionRowBuilder()
            .addComponents(
                new ButtonBuilder()
                    .setLabel('✔')
                    .setCustomId(buttonID1)
                    .setStyle(ButtonStyle.Success)
            )
            .addComponents(
                new ButtonBuilder()
                    .setLabel('✖')
                    .setCustomId(buttonID2)
                    .setStyle(ButtonStyle.Danger)
            )

        await interaction.reply({
            embeds: [embed],
            components: [row],
            flags: MessageFlags.Ephemeral
        })
    }

    const from = interaction.user
    const to = await interaction.options.getUser('target')
    var amount = await interaction.options.getNumber('amount')

    const db = mClient.db(process.env.M_DB)
    const nutsColl = db.collection('items_nuts')
    const yourBalance = await nutsColl.findOne({ userID: from.id })
    const theirBalance = await nutsColl.findOne({ userID: to.id })

    if (amount <= 0) {
        amount = yourBalance.nuts
        return tradeWindow('nuts_give_fake', 'abort')
    }

    if (yourBalance.nuts < amount) {
        return await interaction.reply({
            content: 'Du kannst nicht mehr geben als du hast!',
            flags: MessageFlags.Ephemeral
        })
    }

    return tradeWindow('nuts_give_confirm', 'abort')
}

async function nutsCheck(interaction) {
    let target = interaction.options.getUser('target')
    let addressing

    if (!target) {
        target = interaction.user
        addressing = `Du hast`
    }

    if (!target.globalName) {
        addressing = `${target.username} hat`
    } else {
        addressing = `${target.globalName} hat`
    }

    const db = mClient.db(process.env.M_DB)
    const nutsColl = db.collection('items_nuts')
    const nutsData = await nutsColl.findOne({ userID: target.id })

    let content
    if (!nutsData) {
        content = `${addressing} noch keine Nüsse gesammelt :(`
    } else {
        content = `${addressing} bereits **${nutsData.nuts}** Nüsse gesammelt!`
    }

    let title = 'Zähle Nüsse'
    const embed = new EmbedBuilder()

    for (let i = 0; i < 4; i++) {
        embed.setTitle(title)
        await interaction.editReply({
            embeds: [embed]
        })
        title = title + ' .'
        await delay(500);
    }

    embed
        .setTitle(content)
        .setThumbnail('attachment://nuts_main.png')

    await interaction.editReply({
        embeds: [embed],
        files: [`${asset_path}nuts_main.png`]
    })
}

async function nutsLeaderboard(interaction) {
    const row = new ActionRowBuilder()
        .addComponents(
            new ButtonBuilder()
                .setLabel('◄')
                .setStyle(ButtonStyle.Primary)
                .setCustomId('nuts_leaderboard_left')
        )
        .addComponents(
            new ButtonBuilder()
                .setLabel('🧑')
                .setStyle(ButtonStyle.Primary)
                .setCustomId('nuts_leaderboard_self')
        )
        .addComponents(
            new ButtonBuilder()
                .setLabel('►')
                .setStyle(ButtonStyle.Primary)
                .setCustomId('nuts_leaderboard_right')
        )

    const db = mClient.db(process.env.M_DB)
    const nutsColl = db.collection('items_nuts')
    let skip = 0

    const nutsData = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).skip(skip).limit(5).toArray()

    let fields
    let placements = skip + 1

    nutsData.forEach((data) => {
        fields = (fields ? fields : '') + (`${placements}. <@${data.userID}> : ${data.nuts} Nuts\r\n`)
        placements++
    })

    const embed = new EmbedBuilder()
        .setTitle('Nuts Leaderboard')
        .setThumbnail(interaction.guild.iconURL({ dynamic: true}))
        .setDescription(fields.toString())
        .setColor('#5865F2')
        .setFooter({ text: 'Use ◄ ► to navigate' })

    await interaction.editReply({
        embeds: [embed],
        components: [row]
    })
}

async function nutsStats(interaction) {
    const db = mClient.db(process.env.M_DB);
    const nStatsColl = db.collection('stats_nuts');
    var type = interaction?.options?.getString('type') || 'lookup'
    var target = interaction?.options?.getUser('lookup') || {}

    if (type == 'global') {
        target.id = '__global'
    } else if (!target?.id) {
        target = interaction.user
    }

    const statsDoc = await nStatsColl.findOne({ userID: target.id });
    const stat = statsDoc?.stat || {};

    const totalCount = Object.values(stat).reduce((a, b) => a + b, 0);
    const totalNuts = Object.entries(stat).reduce(
        (sum, [num, count]) => sum + Number(num) * count,
        0
    );

    const rolledNumbers = Object.entries(stat).filter(([_, count]) => count > 0);

    let nutMin = { number: 0, count: 0 };
    let nutMax = { number: 0, count: 0 };

    if (rolledNumbers.length > 0) {
        nutMin = nutMax = { number: Number(rolledNumbers[0][0]), count: rolledNumbers[0][1] };

        for (const [numStr, count] of rolledNumbers) {
            const num = Number(numStr);

            if (count > nutMax.count || (count === nutMax.count && num > nutMax.number)) {
                nutMax = { number: num, count };
            }

            if (count < nutMin.count || (count === nutMin.count && num < nutMin.number)) {
                nutMin = { number: num, count };
            }
        }
    }

    const nutAvg = totalCount ? totalNuts / totalCount : 0;

    const fields = Array.from({ length: 11 }, (_, i) => ({
        name: `[${i}]`,
        value: `x${stat[i] ?? 0}`,
        inline: true
    }));

    const embed = new EmbedBuilder()
        .setTitle("Nut Statistic")
        .setDescription(
            `Total Nut Actions: **${totalCount}**\r\n` +
            `Total Nuts nutted: **${totalNuts}**\r\n` +
            `Nut Average: **${nutAvg.toFixed(3)}**\r\n` +
            `Most Common Nut: **${nutMax.number} (x${nutMax.count})**\r\n` +
            `Least Common Nut: **${nutMin.number} (x${nutMin.count})**`
        )
        .addFields(fields)
        .setColor(0x51267)
        .setTimestamp()
        .setThumbnail('attachment://nuts_main.png')

    await interaction.editReply({
        embeds: [embed],
        files: [`${asset_path}nuts_main.png`]
    });
}

async function nutsCooldown(interaction) {
    const db = mClient.db(process.env.M_DB)
    const nutsColl = db.collection('items_cooldowns')
    const cooldown = await nutsColl.findOne({ userID: interaction.user.id })

    let content = `Du kannst wieder nussen! :)`
    let thumbnail = 'attachment://nuts_main.png'
    let file = `${asset_path}nuts_main.png`
    let title = 'Go Nuts!'

    let date = (Date.now() / 1000)
    if (cooldown.cooldown > date) {
        content = `<t:${cooldown.cooldown}:R> kannst du wieder nussen! ;)`
        thumbnail = 'attachment://nuts_onCD.avif'
        file = `${asset_path}nuts_onCD.avif`
        title = 'To Nut or Not to Nut...'
    }

    const embed = new EmbedBuilder()
        .setThumbnail(thumbnail)
        .setTitle(title)
        .setDescription(content)

    await interaction.editReply({
        embeds: [embed],
        files: [file]
    })
}

async function nutsNut(interaction, quickMode) {
    const db = mClient.db(process.env.M_DB)
    const nutsColl = db.collection('items_nuts')
    const cdColl = db.collection('items_cooldowns')
    const nutsStatsColl = db.collection('stats_nuts')

    const cdData = await cdColl.findOne({ userID: interaction.user.id })
    const embed = new EmbedBuilder()

    const assets = {
        high: 'attachment://nuts_high.jpg',
        normal: 'attachment://nuts_normal.jpg',
        low: 'attachment://nuts_low.jpg',
        none: 'attachment://nuts_none.avif',
        onCD: 'attachment://nuts_onCD.avif',
        box: 'attachment://nuts_box.png',
        explosion: 'attachment://nuts_explosion.gif'
    }

    // Helper for singular/plural
    const formatNut = (amount) => `${amount === 1 ? 'eine' : amount} ${amount === 1 ? 'Nuss' : 'Nüsse'}`

    // check cooldown
    if (cdData?.cooldown > Date.now() / 1000) {
        // on cooldown
        embed.setTitle('To Nut or Not to Nut...')
        embed.setDescription(`<t:${Math.floor(cdData.cooldown)}:R> kannst du wieder nussen! ;)`)
        embed.setThumbnail(assets.onCD)

        return interaction.editReply({
            embeds: [embed],
            files: [`${asset_path}nuts_onCD.avif`]
        })
    }
    // set 1 hour cooldown
    const cd = Math.floor((Date.now() + 3600000) / 1000)
    await cdColl.findOneAndUpdate({
        userID: interaction.user.id
    }, {
        $set: {
            cooldown: cd,
            application: 'nuts'
        }
    }, {
        upsert: true
    })

    // generate nut amount
    const amount = Math.floor(Math.random() * 10)

    // update nuts and stats
    await nutsColl.findOneAndUpdate(
        { userID: interaction.user.id },
        { $inc: { nuts: amount } },
        { upsert: true }
    )

    await nutsStatsColl.findOneAndUpdate(
        { userID: interaction.user.id },
        { $inc: { [`stat.${amount}`]: 1 } },
        { upsert: true }
    )

    await nutsStatsColl.findOneAndUpdate(
        { userID: "__global" },
        { $inc: { [`stat.${amount}`]: 1 } },
        { upsert: true }
    )

    let nutText = `Du hast ${formatNut(amount)} bekommen! :chestnut:`
    if (amount <= 0) {
        nutText = `Du hast keine Nuss bekommen! :yoink_help:`
    }

    if (quickMode) {
        return interaction.editReply({ content: nutText })
    }

    // pseudo animation
    embed.setImage(assets.box)
    await interaction.editReply({
        embeds: [embed],
        files: [`${asset_path}nuts_box.png`]
    })
    await delay(1337)
    embed.setImage(assets.explosion)
    await interaction.editReply({
        embeds: [embed],
        files: [`${asset_path}nuts_explosion.gif`]
    })
    await delay(1337)

    let assetFile
    if (amount === 0) assetFile = assets.none
    else if (amount > 8) assetFile = assets.high
    else if (amount > 4) assetFile = assets.normal
    else assetFile = assets.low

    embed.setTitle(nutText)
    embed.setThumbnail(assetFile)
    embed.setImage(null)

    return interaction.editReply({
        embeds: [embed],
        files: [`${asset_path}${assetFile.split('://')[1]}`]
    })


}
module.exports = {
    data: new SlashCommandBuilder()
        .setName('nuts')
        .setDescription('rund um die nuss')
        .addSubcommand(s =>
            s
                .setName('give')
                .setDescription('gib nuss!!')
                .addUserOption(o => o.setName('target').setDescription('wer bekommt da nuts?').setRequired(true))
                .addNumberOption(o => o.setName('amount').setDescription('wie viele?').setRequired(true)))
        .addSubcommand(s =>
            s
                .setName('check')
                .setDescription('check out deez nuts')
                .addUserOption(o => o.setName('target').setDescription('check out those nuts!')))
        .addSubcommand(s =>
            s
                .setName('leaderboard')
                .setDescription('wer hat die dicksten Nüsse?'))
        .addSubcommand(s =>
            s
                .setName('stats')
                .setDescription('wie viele Nüsse wurden genusst, Genosse?')
                .addStringOption(o =>
                    o.setName('type')
                        .setDescription('set type to global or user')
                        .addChoices(
                            { name: 'global', value: 'global' },
                            { name: 'user', value: 'user' }
                        ),)
                .addUserOption(o =>
                    o.setName('lookup')
                        .setDescription('look up specific user nut statistic')
                )
        )

        .addSubcommand(s =>
            s
                .setName('cooldown')
                .setDescription('wie lange bis ich nussen kann?'))
        .addSubcommand(s =>
            s
                .setName('nut')
                .setDescription('willst du nuss?'))
        .addSubcommand(s =>
            s.setName('quick')
                .setDescription('A quick nut, mlord?')

        ),
    async execute(interaction) {
        switch (interaction.options._subcommand) {
            case 'give':
                nutsGive(interaction)
                break;
            case 'check':
                await interaction.deferReply()
                nutsCheck(interaction)
                break;
            case 'leaderboard':
                await interaction.deferReply()
                nutsLeaderboard(interaction)
                break;
            case 'stats':
                await interaction.deferReply()
                nutsStats(interaction)
                break;
            case 'cooldown':
                await interaction.deferReply()
                nutsCooldown(interaction)
                break;
            case 'nut':
                await interaction.deferReply()
                nutsNut(interaction, false)
                break;
            case 'quick':
                await interaction.deferReply()
                nutsNut(interaction, true)
                break;
            default:
                break;
        }
    }
}
