const { ModalBuilder, UserSelectMenuBuilder, TextInputBuilder, EmbedBuilder, TimestampStyles, time, StringSelectMenuBuilder, messageLink } = require("@discordjs/builders");
const { ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } = require('discord.js')
const { SlashCommandBuilder, LabelBuilder, TextInputStyle, MessageFlags } = require("discord.js");
const { mClient } = require("../../..");
const db = mClient.db('neo-db')
require('dotenv').config()

function getRemaining(timer) {
    if (timer.state !== 'running') {
        return timer.timeRemaining;
    }

    return Math.max(
        0,
        timer.timeRemaining - (Date.now() - timer.startedAt)
    );
}

function ordinal(n) {
    const s = ["th", "st", "nd", "rd"];
    const v = n % 100;

    return n + (s[(v - 20) % 10] || s[v] || s[0]);
}

async function wgeStatus(interaction) {

    const wgeColl = db.collection('timer_wge')
    const historyColl = db.collection('history_wge');

    const results = await wgeColl.findOne({
        $and: [
            { debug: false },
            { state: 'running' }
        ]
    })
    if (!results) {
        return interaction.editReply({
            content: 'No WGE Session currently running!',
            flags: MessageFlags.Ephemeral
        })
    }

    const historyCount = await historyColl.countDocuments();
    const iteration = historyCount + 1;

    const createdAt = new Date(results.createdAt)
    const expiresAt = new Date(createdAt.getTime() + Number(results.timeRemaining))

    const embed = new EmbedBuilder()
        .setTitle(`✨ [${ordinal(iteration)}] World's Greatest Expert ✨`)
        .setDescription(
            `<@${results.assignedUser}> is currently the **World's Greatest Expert** in **${results.topic}**.\n\n` +
            `They must submit their entry <t:${Math.floor(expiresAt.getTime() / 1000)}:R>.\n\n` +
            `Thank you, <@${results.assigningUser}>, for the nomination!`
        )

    return interaction.editReply({
        embeds: [embed]
    })
}

async function wgeStart(interaction) {
    const defaultUsers = []
    defaultUsers.push(process.env.D_ID)


    const participantColl = db.collection('items_wge')
    const participants = await participantColl.find({
        status: true
    }).toArray()


    const wgeBaseModal = new ModalBuilder()
        .setCustomId('wgeBaseModal')
        .setTitle("World's Greatest Expert")

    const options = [
        {
            label: 'RANDOM',
            value: process.env.D_ID
        }
    ];

    const participantOptions = await Promise.all(
        participants.map(async (participant) => {
            try {
                const member = await interaction.guild.members.fetch(participant.userID);
                return {
                    label: `${member.displayName} (${member.user.username})`,
                    value: participant.userID
                };
            } catch {
                return null;
            }
        })
    );

    options.push(
        ...participantOptions.filter(option => option !== null)
    );

    // Using StringSelectMenuBuilder because UserSelectMenuBuilder cannot be filtered for now
    const wgeUserCustInput = new StringSelectMenuBuilder()
        .setCustomId('wgeCustUserInput')
        .setMaxValues(1)
        .setMinValues(1)
        .setRequired(true)
        .addOptions(options)

    const wgeTopicInput = new TextInputBuilder()
        .setCustomId('wgeTopicInput')
        .setStyle(TextInputStyle.Short)
        .setRequired(true)

    const wgeTopicLabel = new LabelBuilder()
        .setLabel("And WHAT are they an expert in?")
        .setDescription('Tell me!')
        .setTextInputComponent(wgeTopicInput)

    const wgeCustUserLabel = new LabelBuilder()
        .setLabel('WHO is your greatest expert?')
        .setDescription('Select them')
        .setStringSelectMenuComponent(wgeUserCustInput)

    wgeBaseModal
        .addLabelComponents(wgeCustUserLabel, wgeTopicLabel)

    await interaction.showModal(wgeBaseModal)
}

async function wgeStop(interaction) {
    ;
    const wgeColl = db.collection('timer_wge');

    const timer = await wgeColl.findOne({
        debug: false
    });

    if (!timer) {
        return interaction.reply({
            content: 'Timer not found.',
            flags: MessageFlags.Ephemeral
        });
    }

    // freeze remaining time
    const remaining = getRemaining(timer);

    await wgeColl.updateOne(
        { _id: timer._id },
        {
            $set: {
                timeRemaining: remaining,
                startedAt: null,
                state: 'stopped'
            }
        }
    );

    await interaction.reply({
        content: `🛑 Timer stopped for **${timer.topic}**`
    });
}

async function wgeResume(interaction) {
    ;
    const wgeColl = db.collection('timer_wge');

    const timer = await wgeColl.findOne({
        debug: false
    });

    if (!timer) {
        return interaction.reply({
            content: 'Timer not found.',
            flags: MessageFlags.Ephemeral
        });
    }

    // freeze remaining time
    const remaining = getRemaining(timer);

    await wgeColl.updateOne(
        { _id: timer._id },
        {
            $set: {
                timeRemaining: remaining,
                startedAt: Date.now(),
                state: 'running'
            }
        }
    );

    await interaction.reply({
        content: `🟢 Timer resumed for **${timer.topic}**`
    });
}

async function wgeForfeit(interaction) {
    ;
    const wgeColl = db.collection('timer_wge');
    const participateColl = db.collection('items_wge');

    // Get active WGE
    const wge = await wgeColl.findOne({
        debug: false,
        state: 'running'
    });

    if (!wge) {
        return interaction.reply({
            content: 'No active WGE is currently running.',
            flags: MessageFlags.Ephemeral
        });
    }

    // Sanity check: only assigned user can forfeit
    if (wge.assignedUser !== interaction.user.id) {
        return interaction.reply({
            content: `Only <@${wge.assignedUser}> can forfeit the current WGE.`,
            flags: MessageFlags.Ephemeral
        });
    }

    // Pick a new participant, excluding current assignee
    const [randomParticipant] = await participateColl.aggregate([
        {
            $match: {
                status: true,
                userID: { $ne: interaction.user.id }
            }
        },
        { $sample: { size: 1 } }
    ]).toArray();

    if (!randomParticipant) {
        return interaction.reply({
            content: 'No one else is participating!',
            flags: MessageFlags.Ephemeral
        });
    }

    const member = await interaction.guild.members.fetch(
        randomParticipant.userID
    );

    const nextUser = member.user;

    const WGE_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 days

    await wgeColl.deleteOne({ _id: wge._id });

    await wgeColl.insertOne({
        assignedUser: nextUser.id,
        assigningUser: wge.assigningUser,

        startedAt: Date.now(),
        timeRemaining: WGE_DURATION,

        state: 'running',

        notifications: {
            half: false,
            day24: false,
            complete: false
        },

        topic: wge.topic,
        debug: false,

        createdAt: new Date()
    });

    return interaction.reply({
        content: `${interaction.user} has forfeited! <@${nextUser.id}> is the next expert! Their topic is **${wge.topic}**`
    });
}

async function wgeParticipate(interaction) {
    const status = interaction.options.getBoolean('status')
    const user = interaction.user

    const coll = db.collection('items_wge')

    // Choice was false, ergo not participating
    await coll.findOneAndUpdate({
        userID: user.id
    }, {
        $set: {
            userID: user.id,
            status: status
        }
    }, {
        upsert: true
    })

    interaction.reply({
        content: `You are ${status ? '' : 'no longer '}participating!`,
        flags: MessageFlags.Ephemeral
    })
}

async function listParticipants(interaction) {
    ;
    const participantColl = db.collection('items_wge');
    const participants = await participantColl.find({}).toArray();

    const participating = participants
        .filter(p => p.status)
        .map(p => `<@${p.userID}>`);

    const notParticipating = participants
        .filter(p => !p.status)
        .map(p => `<@${p.userID}>`);

    const embed = new EmbedBuilder()
        .setTitle('WGE Participation')
        .setColor(0x5865F2)
        .addFields(
            {
                name: `Participating (${participating.length})`,
                value: participating.join('\n') || 'No participants found.',
                inline: true
            },
            {
                name: `Not Participating (${notParticipating.length})`,
                value: notParticipating.join('\n') || 'No entries found.',
                inline: true
            }
        )
        .setFooter({
            text: `Total entries: ${participants.length}`
        })

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

function formatDuration(ms) {
    if (ms == null) return "unknown"

    const totalSeconds = Math.floor(ms / 1000)
    const days = Math.floor(totalSeconds / 86400)
    const hours = Math.floor((totalSeconds % 86400) / 3600)
    const minutes = Math.floor((totalSeconds % 3600) / 60)
    const seconds = totalSeconds % 60

    const parts = []

    if (days) parts.push(`${days}d`)
    if (hours) parts.push(`${hours}h`)
    if (minutes) parts.push(`${minutes}m`)
    if (seconds && !days) parts.push(`${seconds}s`) // only show seconds for short durations

    return parts.length ? parts.join(" ") : "0s"
}

async function listHistory(interaction) {
    const historyColl = db.collection('history_wge')

    const wgeHistory = await historyColl
        .find({ debug: false })
        .sort({ createdAt: -1 })
        .toArray()

    if (!wgeHistory.length) {
        return interaction.reply({
            content: "No WGE history found.",
            flags: MessageFlags.Ephemeral
        })
    }

    const buildEmbed = (entry, index) => {
        const createdTs = entry.createdAt
            ? Math.floor(new Date(entry.createdAt).getTime() / 1000)
            : null

        return new EmbedBuilder()
            .setTitle(`WGE History (${index + 1}/${wgeHistory.length})`)
            .setDescription(
                `<@${entry.assignedUser}> was the **World's Greatest Expert** of...\n\n` +
                `**${entry.topic}**\n\n` +
                
                `Assigned by: <@${entry.assigningUser}>\n` +
                (createdTs ? `Created: <t:${createdTs}:R>` : "")
            )
            .setColor(0x2b2d31)
    }

    let page = 0

    const row = new ActionRowBuilder().addComponents(
        new ButtonBuilder()
            .setCustomId('prev')
            .setLabel('◀')
            .setStyle(ButtonStyle.Secondary)
            .setDisabled(true),

        new ButtonBuilder()
            .setCustomId('next')
            .setLabel('▶')
            .setStyle(ButtonStyle.Secondary)
            .setDisabled(wgeHistory.length <= 1)
    )

    const msg = await interaction.reply({
        embeds: [buildEmbed(wgeHistory[page], page)],
        components: [row],
        fetchReply: true
    })

    const collector = msg.createMessageComponentCollector({
        componentType: ComponentType.Button,
        time: 120000
    })

    collector.on('collect', async i => {
        if (i.user.id !== interaction.user.id) {
            return i.reply({
                content: "You can't control this pagination.",
                flags: MessageFlags.Ephemeral
            })
        }

        if (i.customId === 'prev') {
            page--
        } else if (i.customId === 'next') {
            page++
        }

        page = Math.max(0, Math.min(page, wgeHistory.length - 1))

        row.components[0].setDisabled(page === 0)
        row.components[1].setDisabled(page === wgeHistory.length - 1)

        await i.update({
            embeds: [buildEmbed(wgeHistory[page], page)],
            components: [row]
        })
    })

    collector.on('end', async () => {
        const disabledRow = new ActionRowBuilder().addComponents(
            row.components.map(btn => ButtonBuilder.from(btn).setDisabled(true))
        )

        await msg.edit({ components: [disabledRow] }).catch(() => { })
    })
}

async function wgeList(interaction) {
    const thing = interaction.options.getString('thing');

    switch (thing) {
        case 'participants': {
            listParticipants(interaction)
            break;
        }
        case 'history':
            listHistory(interaction)
            break;
        default:
            break;
    }
}

module.exports = {
    data: new SlashCommandBuilder()
        .setName('wge')
        .setDescription('welcome to worlds greatest experts')
        // Show Status of Current Running WGE Session
        .addSubcommand(s =>
            s
                .setName('status')
                .setDescription('display current wge session')
        )

        // Assign Someone to be the next Expert
        .addSubcommand(s =>
            s
                .setName('start')
                .setDescription('start a new wge session')
        )

        // Stop the current Session Timer
        .addSubcommand(s =>
            s
                .setName('stop')
                .setDescription('stop the current wge session')
        )

        // Resume the current Session Timer
        .addSubcommand(s =>
            s
                .setName('resume')
                .setDescription('resume the current wge session timer')
        )

        // Forfeit your current expert topic and assign someone else
        .addSubcommand(s =>
            s
                .setName('forfeit')
                .setDescription('forfeit your current topic')
        )

        // List the previous WGE Sessions
        .addSubcommand(s =>
            s
                .setName('history')
                .setDescription('display the previous wge sessions')
        )

        // List the previous WGE Sessions
        .addSubcommand(s =>
            s
                .setName('participate')
                .setDescription('do you want to play a game?')
                .addBooleanOption(o =>
                    o.setName('status')
                        .setDescription('choose')
                        .setRequired(true)
                )
        )

        // List the previous WGE Sessions
        .addSubcommand(s =>
            s
                .setName('list')
                .setDescription('list things')
                .addStringOption(o =>
                    o.setName('thing')
                        .setDescription('what would you like to be listed')
                        .addChoices(
                            { name: 'participants', value: 'participants' },
                            { name: 'history', value: 'history' }
                        )
                )
        )
    ,
    async execute(interaction) {
        switch (interaction.options._subcommand) {
            case 'status':
                await interaction.deferReply()
                wgeStatus(interaction)
                break;
            case 'start':
                wgeStart(interaction)
                break;
            case 'stop':
                wgeStop(interaction)
                break;
            case 'pause':
                wgePause(interaction)
                break;
            case 'resume':
                wgeResume(interaction)
                break;
            case 'forfeit':
                wgeForfeit(interaction)
                break;
            case 'history':
                wgeHistory(interaction)
                break;
            case 'participate':
                wgeParticipate(interaction)
                break;
            case 'list':
                wgeList(interaction)
            default:
                break;
        }
    }
}