import { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits, MessageFlags } from "discord.js"
import type { ChatInputCommandInteraction, APIEmbedField } from "discord.js"
import dbGuildInit from "@/utils/dbGuildInit"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"

const parseObject = (obj: object, prefix = ""): { name: string, value: object | string | boolean }[] => {
	const fields: { name: string, value: object | string | boolean }[] = []

	for (const [key, value] of Object.entries(obj)) {
		if (value !== null && typeof value === "object") fields.push(...parseObject(value as object, `${prefix}${key}.`))
		else {
			let newValue: string
			if (typeof value === "boolean") newValue = value ? "True" : "False"
			else if (value === null || value === undefined) newValue = "None"
			else newValue = String(value)

			fields.push({ name: `${prefix}${key}`, value: newValue })
		}
	}
	return fields
}

export const data = new SlashCommandBuilder()
	.setName("database")
	.setDescription("Communicate with the database")
	.setDescriptionLocalizations({ fr: "Communiquer avec la base de données" })
	.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
	.addSubcommand(subcommand => subcommand
		.setName("info")
		.setDescription("Returns information about the current guild")
		.setNameLocalizations({ fr: "info" })
		.setDescriptionLocalizations({ fr: "Retourne les informations sur le serveur actuel" })
	)
	.addSubcommand(subcommand => subcommand
		.setName("init")
		.setDescription("Force initialize an entry for the current guild in the database")
		.setNameLocalizations({ fr: "init" })
		.setDescriptionLocalizations({ fr: "Initialiser de force une entrée pour le serveur actuel dans la base de données" })
	)
	.addSubcommand(subcommand => subcommand
		.setName("edit")
		.setDescription("Modify parameters for the current guild")
		.setNameLocalizations({ fr: "modifier" })
		.setDescriptionLocalizations({ fr: "Modifier les paramètres pour le serveur actuel" })
		.addStringOption(option => option
			.setName("key")
			.setDescription("Key to modify")
			.setNameLocalizations({ fr: "cle" })
			.setDescriptionLocalizations({ fr: "Clé à modifier" })
			.setRequired(true)
		)
		.addStringOption(option => option
			.setName("value")
			.setDescription("Value to set")
			.setNameLocalizations({ fr: "valeur" })
			.setDescriptionLocalizations({ fr: "Valeur à définir" })
			.setRequired(true)
		)
	)

export async function execute(interaction: ChatInputCommandInteraction) {
	if (interaction.user !== interaction.client.application.owner) return interaction.reply({ content: t(interaction.locale, "database.owner_only"), flags: MessageFlags.Ephemeral })

	const guild = interaction.guild
	if (!guild) return interaction.reply({ content: t(interaction.locale, "database.server_only"), flags: MessageFlags.Ephemeral })

	let guildProfile = await dbGuild.findOne({ guildId: guild.id })

	const subcommand = interaction.options.getSubcommand(true)
	if (subcommand === "info") {
		if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })

		const fields = parseObject(guildProfile.toObject())
		const embed = new EmbedBuilder()
			.setTitle(t(interaction.locale, "database.info_title"))
			.setDescription(t(interaction.locale, "database.guild_info", { name: guildProfile.guildName, id: guildProfile.guildId }))
			.setThumbnail(guildProfile.guildIcon)
			.setTimestamp()
			//.addFields(fields as APIEmbedField[])
			// Limit the number of fields to 25
			.addFields(fields.slice(0, 25) as APIEmbedField[])

		return interaction.reply({ embeds: [embed] })
	}
	else if (subcommand === "init") {
		if (guildProfile) return interaction.reply({ content: t(interaction.locale, "database.already_exists", { name: guildProfile.guildName }), flags: MessageFlags.Ephemeral })

		guildProfile = await dbGuildInit(guild)

		return interaction.reply({ content: t(interaction.locale, "database.initialized", { name: guildProfile.guildName }), flags: MessageFlags.Ephemeral })
	}
	else if (subcommand === "edit") {
		if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })

		const key = interaction.options.getString("key", true)
		const value = interaction.options.getString("value", true)

		let oldValue: string = guildProfile.get(key) as string
		if (!oldValue) oldValue = t(interaction.locale, "common.none")

		guildProfile.set(key, value)
		guildProfile.markModified(key)
		await guildProfile.save().catch(console.error)

		return interaction.reply({ content: t(interaction.locale, "database.updated", { name: guildProfile.guildName, key, oldValue, value }), flags: MessageFlags.Ephemeral })
	}
}
