const { SlashCommandBuilder, AttachmentBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } = require("discord.js");
const { Card, User, Group, Character, Badge } = require("../models");
const { Rendering, UserUtils } = require("../util");
const { QUALITY_NAMES } = require("../config/constants");
const fs = require("fs");
const edit = require("./edit");

//fetch all cards owned by the user and list them
module.exports = {
    data: new SlashCommandBuilder()
            .setName("view")
            .setDescription("View a specific thing")
            .addStringOption((option) =>
                option
                    .setName("type")
                    .setDescription("The thing to view")
                    .setRequired(true)
                    .addChoices(
                        { name: 'badge', value: 'badge' },
                        { name: 'card', value: 'card' },
                        { name: 'character', value: 'character' },
                        { name: 'group', value: 'group' }
                    )
                )
            .addStringOption((option) =>
                option
                    .setName("id")
                    .setDescription("Thing identifier")
                    .setRequired(true)
                    .setAutocomplete(true)
                ),
    permissionLevel: 0,
    async execute(interaction) {
        await interaction.deferReply();

        switch (interaction.options.getString("type")) {
            case "badge":
                this.viewBadge(interaction, interaction.options.getString("id"));
                break;
            case "card":
                this.viewCard(interaction, interaction.options.getString("id"));
                break;
            case "character":
                this.viewCharacter(interaction, interaction.options.getString("id"));
                break;
            case "group":
                interaction.editReply({ content: "Group view is not yet implemented" });
                break;

        }
    },

    /**
     * View a card by its identifier and create an embed for it
     * @param {Interaction} interaction - The interaction object that triggered this function
     * @param {string} cardIdentifier - The identifier of the card to view
     * @returns {Promise<void>} - A promise that resolves once the card has been viewed and an embed has been created
     */
    async viewCard(interaction, cardIdentifier) {
        let card = await Card.findOne({
            where: {
                identifier: cardIdentifier
            },
            include: [
                { model: Character, include: [{ model: Group }] },
                { model: User}
            ]
        });
        if (card === null) {
            interaction.editReply({ content: "Card not found" });
            return;
        }
        let cardImage = await Rendering.renderCard(card).catch(async err => {
            await interaction.channel.send(`Uooh an error! ${err.response?.status} ${err.response?.statusText} \n ${err.response?.data.message} \n ${err.response?.data.jobId}`);
        });
        if (!cardImage) { return; }
        
        let description = "";
        //Add a new line after every 4th (long) word or after a full stop
        let words = card.Character.description.split(" ");
        let count = 0;
        for (let i = 0; i < words.length; i++) {
            description += words[i] + " ";
            if (words[i].length > 3) {
                count++;
            }
            if (count >= 4 || words[i].endsWith(".")) {
                description += "\n";
                count = 0;
            }
        }

        const embed = new EmbedBuilder()
            .setTitle(`${card.Character.name}`)
            .setDescription(description)
            .setImage(cardImage)
            .setThumbnail(card.Character.Group.imageURL)
            .addFields(
                { name: "Owned by", value: `<@${card.User.discordId}>` },
                { name: "Group", value: `${card.Character.Group.name}` },
                { name: "Character ID", value: `${card.Character.id}` },
                { name: 'Print Number', value: `${card.printNr}`, inline: true },
                { name: 'Quality', value: `${QUALITY_NAMES[card.quality]} ${(card.quality === 6 ? '<a:sparklu:1019505245572837428>':'')}`, inline: true }
            )
            .setColor(0x00ff00)
            .setFooter({ text: `${card.identifier}`, iconURL: 'https://cdn.discordapp.com/attachments/856904078754971658/1017431187234508820/fp.png' })
            .setTimestamp(card.createdAt);
        if (card.burned) {
            embed.setColor(0xff0000);
            embed.addFields({ name: "Burned", value: "This card has been burned" });
        }
        const message = await interaction.editReply({ embeds: [embed], fetchReply: true });
    },

    /**
     * View a character by its ID and create an embed for it.
     * If the member who triggered the interaction is an admin, also include an "Edit" button.
     * (Edits the passed interaction reply)
     * 
     * @param {Interaction} interaction - The interaction object that triggered this function.
     * @param {number} characterId - The ID of the character to view.
     * @returns {Promise<void>} - A promise that resolves once the character has been viewed and an embed has been created.
     */
    async viewCharacter(interaction, characterId) {
        let isAdmin = await UserUtils.getPermissionLevel(interaction.member) == 2;
        let character = await Character.findOne({ 
            where: { id: characterId },
            include: [Group]
        });
        if (!character) {
            interaction.editReply({ content: "Character not found" });
            return;
        }
        let imagePath = `./assets/cards/${character.imageIdentifier}`;
        //if image doesn't exist, use placeholder
        if (!fs.existsSync(imagePath)) {
            imagePath = "./assets/cards/missing_image.png";
        }

        //get base filename
        let filename = imagePath.split("/").pop();

        let description = "";
        //Add a new line after every 4th (long) word or after a full stop
        let words = character.description.split(" ");
        let count = 0;
        for (let i = 0; i < words.length; i++) {
            description += words[i] + " ";
            if (words[i].length > 3) {
                count++;
            }
            if (count >= 4 || words[i].endsWith(".")) {
                description += "\n";
                count = 0;
            }
        }

        const embed = new EmbedBuilder()
            .setTitle(`${character.name}`)
            .setDescription(description)
            .setImage(`attachment://${filename}`)
            .setThumbnail(character.Group.imageURL)
            .addFields(
                { name: "Group", value: `${character.Group.name}` },
                { name: "Character ID", value: `${character.id}` },
            )
            .setColor(0x00ff00)

        let row;
        if (isAdmin) {
            row = new ActionRowBuilder()
                .addComponents(
                    new ButtonBuilder()
                        .setCustomId(`edit-char-${character.id}`)   
                        .setLabel("Edit") 
                        .setStyle(ButtonStyle.Danger)
                );
        }
        let replyPayload = { embeds: [embed], files: [imagePath], fetchReply: true }

        //the experimental Edit button is added if view is invoked by an admin
        if  (isAdmin) { replyPayload.components = [row]; }
        const message = await interaction.editReply(replyPayload);
        const filter = (m) => m.member.user.id === interaction.member.user.id;
        const collector = message.createMessageComponentCollector({ filter, componentType: ComponentType.Button, time: 120000 });

        collector.on('collect', async (m) => {
            console.log(`Collected ${m.customId}`);
            if (m.customId === `edit-char-${character.id}`) {
                await edit.execute(m, 'character', character.id);
            }
        });
    },

    /**
     * View a badge by its ID and create an embed for it
     * (Edits the passed interaction reply)
     * 
     * @async
     * @param {Interaction} interaction - The interaction object that triggered this function
     * @param {number} badgeId - The ID of the badge to view
     * @returns {Promise<void>} - A promise that resolves once the badge has been viewed and an embed has been created
     */
    async viewBadge(interaction, badgeId) {
        let badge = await Badge.findOne({ 
            where: { id: badgeId },
            include: [Character]
        });

        let required = "";
        badge.Characters.forEach(character => {
            required += `_[${character.id}]_ ${character.name} \n`;
        });

        const embed = new EmbedBuilder()
            .setTitle(`${badge.name}`)
            .setDescription(badge.description)
            .setImage(badge.image)
            .addFields(
                { name: "Required characters:", value: `${required}` },
            )
            .setColor(0x00ff00)
            .setFooter({ text: `Badge viewed by ${interaction.member.displayName}` });

        let replyPayload = { embeds: [embed], fetchReply: true }
        const message = await interaction.editReply(replyPayload);
    }
}