package me.money.boxplugin.Gifts

import me.money.boxplugin.BoxPlugin
import me.money.boxplugin.config.Config
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.Sound
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
import java.time.Duration
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.TextDecoration

class GiftGui(private val plugin: BoxPlugin) : Listener {
    init {
        Bukkit.getPluginManager().registerEvents(this, plugin)
    }

    fun openGui(player: Player) {
        val inventory = Bukkit.createInventory(null, 36, Config.giftGuiTitle)
        updateInventory(inventory, player)
        player.openInventory(inventory)
    }

    private fun updateInventory(inventory: Inventory, player: Player) {
        inventory.clear()

        val claimedGifts = plugin.gifts.getPlayerClaimedGifts(player)
        val onlineTime = plugin.gifts.getPlayerOnlineTime(player)
        val timeUntilReset = plugin.gifts.getTimeUntilReset()

        // Set background
        val backgroundMaterial = Material.valueOf(Config.giftGuiBackgroundMaterial)
        val backgroundItem = ItemStack(backgroundMaterial).apply {
            itemMeta = itemMeta?.apply {
                displayName(Component.empty())
                lore(listOf(Component.text(backgroundMaterial.name)))
            }
        }
        for (i in 0 until inventory.size) {
            inventory.setItem(i, backgroundItem)
        }

        // Center the 5 gifts in slots 11-15
        GiftTier.entries.forEachIndexed { index, giftTier ->
            val item = if (giftTier in claimedGifts) {
                createClaimedItem(index, giftTier)
            } else if (onlineTime >= giftTier.requiredMinutes) {
                createUnlockedItem(index, giftTier)
            } else {
                createLockedItem(index, giftTier, onlineTime)
            }
            inventory.setItem(11 + index, item)
        }

        // Add reset time information
        val resetInfoItem = createResetInfoItem(timeUntilReset)
        inventory.setItem(31, resetInfoItem)
    }

    private fun createClaimedItem(index: Int, giftTier: GiftTier): ItemStack {
        val claimedMaterial = Material.valueOf(Config.giftClaimedMaterial)
        return ItemStack(claimedMaterial).apply {
            itemMeta = itemMeta?.apply {
                displayName(Config.miniMessage.deserialize(Config.giftClaimedTitle.replace("%number%", "${index + 1}")))
                lore(Config.giftClaimedLore.map { line ->
                    Config.miniMessage.deserialize(line
                        .replace("%coins%", giftTier.baseCoins.toString())
                        .replace("%reward-name%", Config.getGiftTierRewardName(giftTier.name.lowercase()))
                    ).decoration(TextDecoration.ITALIC, false)
                })
            }
        }
    }

    private fun createUnlockedItem(index: Int, giftTier: GiftTier): ItemStack {
        val unlockedMaterial = Material.valueOf(Config.giftUnlockedMaterial)
        return ItemStack(unlockedMaterial).apply {
            itemMeta = itemMeta?.apply {
                val lore = mutableListOf<Component>()

                val itemName = Config.getGiftTierItemName(giftTier.name.lowercase())
                lore.add(Config.miniMessage.deserialize("<gray>- $itemName</gray>").decoration(TextDecoration.ITALIC, false))



                displayName(Config.miniMessage.deserialize(Config.giftUnlockedTitle.replace("%number%", "${index + 1}")))
                lore(Config.giftUnlockedLore.map { line ->
                    Config.miniMessage.deserialize(line
                        .replace("%coins%", giftTier.baseCoins.toString())
                        .replace("%reward%", Config.getGiftTierRewardName(giftTier.name.lowercase()))
                    ).decoration(TextDecoration.ITALIC, false)

                })
            }
        }
    }

    private fun createLockedItem(index: Int, giftTier: GiftTier, onlineTime: Long): ItemStack {
        val lockedMaterial = Material.valueOf(Config.giftLockedMaterial)
        return ItemStack(lockedMaterial).apply {
            itemMeta = itemMeta?.apply {

                val lore = mutableListOf<Component>()
                val itemName = Config.getGiftTierItemName(giftTier.name.lowercase())
                lore.add(Config.miniMessage.deserialize("<gray>- $itemName</gray>").decoration(TextDecoration.ITALIC, false))

                displayName(Config.miniMessage.deserialize(Config.giftLockedTitle.replace("%number%", "${index + 1}")))
                lore(Config.giftLockedLore.map { line ->
                    Config.miniMessage.deserialize(line
                        .replace("%time%", formatDuration(Duration.ofMinutes(maxOf(0, giftTier.requiredMinutes - onlineTime))))
                        .replace("%coins%", giftTier.baseCoins.toString())
                        .replace("%reward%", Config.getGiftTierRewardName(giftTier.name.lowercase()))
                        .let { if (!it.contains("%reward%")) it else it.replace(" and %reward%", "") }
                    ).decoration(TextDecoration.ITALIC, false)
                })
            }
        }
    }

    private fun createResetInfoItem(timeUntilReset: Duration): ItemStack {
        val resetInfoMaterial = Material.valueOf(Config.giftResetInfoMaterial)
        return ItemStack(resetInfoMaterial).apply {
            itemMeta = itemMeta?.apply {
                displayName(Config.miniMessage.deserialize(Config.giftResetInfoTitle))
                lore(Config.giftResetInfoLore.map { line ->
                    Config.miniMessage.deserialize(line
                        .replace("%time%", formatDuration(timeUntilReset))
                    ).decoration(TextDecoration.ITALIC, false)
                })
            }
        }
    }

    private fun formatDuration(duration: Duration): String {
        val hours = duration.toHours()
        val minutes = duration.toMinutesPart()
        return Config.timeFormat.replace("%hours%", hours.toString()).replace("%minutes%", minutes.toString())
    }

    @EventHandler
    fun onInventoryClick(event: InventoryClickEvent) {
        if (event.view.title() == Config.giftGuiTitle) {
            event.isCancelled = true
            val clickedSlot = event.rawSlot
            if (clickedSlot in 11..15) {
                val player = event.whoClicked as? Player ?: return
                val giftTier = GiftTier.entries[clickedSlot - 11]
                val onlineTime = plugin.gifts.getPlayerOnlineTime(player)

                if (onlineTime >= giftTier.requiredMinutes && !plugin.gifts.getPlayerClaimedGifts(player).contains(giftTier)) {
                    plugin.gifts.claimGift(player, giftTier)
                    player.playSound(player.location, Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.0f)
                    updateInventory(event.inventory, player)
                }
            }
        }
    }
}

---

package me.money.boxplugin.Gifts

import me.money.boxplugin.BoxPlugin
import me.money.boxplugin.config.Config
import me.money.boxplugin.data.DatabaseManager
import org.bson.Document
import org.bukkit.Bukkit
import org.bukkit.Sound
import org.bukkit.entity.Player
import org.bukkit.scheduler.BukkitTask
import java.util.*
import java.time.Instant
import java.time.Duration

class Gifts(private val plugin: BoxPlugin) {
    val playerTimes: MutableMap<UUID, Long> = mutableMapOf()
    val playerClaimedGifts: MutableMap<UUID, MutableSet<GiftTier>> = mutableMapOf()
    private var resetTime: Instant = Instant.now().plus(Duration.ofHours(24))
    private var resetTask: BukkitTask? = null

    init {
        loadData()
        startResetTask()
        startTimeTrackingTask()
    }

    private fun loadData() {
        val collection = DatabaseManager.getInstance(plugin).collection
        val giftData = collection.find(Document("type", "gift_data")).firstOrNull()
        if (giftData != null) {
            resetTime = Instant.ofEpochMilli(giftData.getLong("resetTime"))
            playerTimes.putAll((giftData["playerTimes"] as? Map<String, Long>)?.mapKeys { UUID.fromString(it.key) } ?: emptyMap())
            playerClaimedGifts.putAll((giftData["playerClaimedGifts"] as? Map<String, List<String>>)?.mapKeys { UUID.fromString(it.key) }?.mapValues { entry -> entry.value.map { GiftTier.valueOf(it) }.toMutableSet() } ?: emptyMap())
        } else {
            resetTime = Instant.now().plus(Duration.ofHours(24))
        }
    }

    fun saveData() {
        val collection = DatabaseManager.getInstance(plugin).collection
        val giftData = Document(mapOf(
            "type" to "gift_data",
            "resetTime" to resetTime.toEpochMilli(),
            "playerTimes" to playerTimes.mapKeys { it.key.toString() },
            "playerClaimedGifts" to playerClaimedGifts.mapKeys { it.key.toString() }.mapValues { (_, gifts) -> gifts.map { it.name } }
        ))

        collection.updateOne(
            Document("type", "gift_data"),
            Document("\$set", giftData),
            com.mongodb.client.model.UpdateOptions().upsert(true)
        )
    }

    private fun startResetTask() {
        resetTask = Bukkit.getScheduler().runTaskTimer(plugin, Runnable {
            if (Instant.now().isAfter(resetTime)) {
                playerTimes.clear()
                playerClaimedGifts.clear()
                resetTime = Instant.now().plus(Duration.ofHours(24))
                saveData()
            }
        }, 0L, 20L * 60L) // Run every minute
    }

    private fun startTimeTrackingTask() {
        Bukkit.getScheduler().runTaskTimer(plugin, Runnable {
            for (player in Bukkit.getOnlinePlayers()) {
                val uuid = player.uniqueId
                playerTimes[uuid] = (playerTimes[uuid] ?: 0) + 1
                checkAndClaimGifts(player)
            }
            saveData()
        }, 0L, 20L * 60L) // Run every minute
    }

    private fun checkAndClaimGifts(player: Player) {
        val time = playerTimes[player.uniqueId] ?: 0
        val claimedGifts = playerClaimedGifts.getOrPut(player.uniqueId) { mutableSetOf() }
        val newlyUnlockedGifts = GiftTier.entries.filter { it.requiredMinutes <= time && it !in claimedGifts }

        if (newlyUnlockedGifts.isNotEmpty()) {
            player.playSound(player.location, Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.0f)
            player.sendMessage(Config.miniMessage.deserialize(Config.giftUnlockedMessage.replace("%count%", newlyUnlockedGifts.size.toString())))
            saveData()
        }
    }

    fun claimGift(player: Player, giftTier: GiftTier) {
        val uuid = player.uniqueId
        val claimedGifts = playerClaimedGifts.getOrPut(uuid) { mutableSetOf() }

        if (giftTier !in claimedGifts) {
            val coins = giftTier.baseCoins
            DatabaseManager.getInstance(plugin).profiles[uuid]?.let { profile ->
                profile.coins += coins
            }

            // Play a satisfying sound
            val sound = Config.getGiftClaimSound()
            player.playSound(player.location, sound.sound, sound.volume, sound.pitch)

            claimedGifts.add(giftTier)

            // Execute the reward commands
            val rewardCommands = Config.getGiftTierRewardCommands(giftTier.name.lowercase())
            for (command in rewardCommands) {
                try {
                    val formattedCommand = command.replace("%player%", player.name)
                    plugin.logger.info("Executing command for ${giftTier.name}: $formattedCommand")
                    val success = Bukkit.dispatchCommand(Bukkit.getConsoleSender(), formattedCommand)
                    if (!success) {
                        plugin.logger.warning("Command execution failed for ${giftTier.name}: $formattedCommand")
                    }
                } catch (e: Exception) {
                    plugin.logger.severe("Error executing reward command for ${giftTier.name}: ${e.message}")
                }
            }
        }
    }



    fun unclaimAllGifts(player: Player): Int {
        val uuid = player.uniqueId
        val claimedGifts = playerClaimedGifts.getOrPut(uuid) { mutableSetOf() }
        val unclaimedCount = claimedGifts.size

        claimedGifts.clear()
        playerTimes[uuid] = 0L

        saveData()
        return unclaimedCount
    }


    fun getPlayerClaimedGifts(player: Player): Set<GiftTier> {
        return playerClaimedGifts[player.uniqueId] ?: emptySet()
    }

    fun getPlayerOnlineTime(player: Player): Long {
        return playerTimes[player.uniqueId] ?: 0
    }

    fun getTimeUntilReset(): Duration {
        return Duration.between(Instant.now(), resetTime)
    }
}

---

package me.money.boxplugin.Gifts

import me.money.boxplugin.config.Config

enum class GiftTier(private val tierName: String) {
    ONE("one"),
    TWO("two"),
    THREE("three"),
    FOUR("four"),
    FIVE("five");

    val requiredMinutes: Long
        get() = Config.getGiftTierMinutes(tierName)

    val baseCoins: Int
        get() = Config.getGiftTierCoins(tierName)
}


fix this code make it work better