package fr.luc.gamingcore.manager;

import fr.luc.gamingcore.model.Guild;
import fr.luc.gamingcore.model.GuildInvite;
import org.bukkit.entity.Player;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Gestionnaire des invitations temporaires envoyées aux joueurs pour intégrer une guilde.
 */
public class InviteManager {

    // Map: Target Player UUID -> Map(Guild UUID -> GuildInvite)
    private final Map<UUID, Map<UUID, GuildInvite>> invites = new ConcurrentHashMap<>();
    private final long defaultDurationMillis = 60L * 1000L; // 60 secondes

    /**
     * Envoie ou renouvelle une invitation pour un joueur vers une guilde.
     *
     * @param guild  La guilde émettrice.
     * @param sender Le joueur qui a initié l'invitation.
     * @param target Le joueur invité.
     * @return L'instance GuildInvite créée.
     */
    public GuildInvite sendInvite(Guild guild, Player sender, Player target) {
        return sendInvite(guild, sender, target, defaultDurationMillis);
    }

    /**
     * Envoie une invitation avec une durée personnalisée.
     *
     * @param guild          La guilde émettrice.
     * @param sender         Le joueur émetteur.
     * @param target         Le joueur destinataire.
     * @param durationMillis Durée de validité de l'invitation en millisecondes.
     * @return L'instance GuildInvite créée.
     */
    public GuildInvite sendInvite(Guild guild, Player sender, Player target, long durationMillis) {
        if (guild == null || sender == null || target == null) {
            return null;
        }

        GuildInvite invite = new GuildInvite(guild.getId(), target.getUniqueId(), sender.getUniqueId(), durationMillis);
        invites.computeIfAbsent(target.getUniqueId(), k -> new ConcurrentHashMap<>())
                .put(guild.getId(), invite);

        return invite;
    }

    /**
     * Récupère une invitation active et non expirée pour un joueur et une guilde donnés.
     *
     * @param target  Le joueur invité.
     * @param guildId L'UUID de la guilde.
     * @return L'invitation valide ou null si inexistante ou expirée.
     */
    public GuildInvite getValidInvite(Player target, UUID guildId) {
        if (target == null || guildId == null) return null;
        Map<UUID, GuildInvite> playerInvites = invites.get(target.getUniqueId());
        if (playerInvites == null) return null;

        GuildInvite invite = playerInvites.get(guildId);
        if (invite != null) {
            if (invite.isExpired()) {
                playerInvites.remove(guildId);
                return null;
            }
            return invite;
        }
        return null;
    }

    /**
     * Vérifie si un joueur possède une invitation valide non expirée pour une guilde.
     *
     * @param target  Le joueur cible.
     * @param guildId L'UUID de la guilde.
     * @return true si une invitation valide existe, false sinon.
     */
    public boolean hasValidInvite(Player target, UUID guildId) {
        return getValidInvite(target, guildId) != null;
    }

    /**
     * Supprime une invitation (suite à une acceptation, un refus ou une annulation).
     *
     * @param target  Le joueur invité.
     * @param guildId L'UUID de la guilde.
     */
    public void removeInvite(Player target, UUID guildId) {
        if (target == null || guildId == null) return;
        Map<UUID, GuildInvite> playerInvites = invites.get(target.getUniqueId());
        if (playerInvites != null) {
            playerInvites.remove(guildId);
            if (playerInvites.isEmpty()) {
                invites.remove(target.getUniqueId());
            }
        }
    }

    /**
     * Nettoie toutes les invitations expirées du cache mémoire.
     */
    public void cleanExpired() {
        invites.forEach((uuid, map) -> {
            map.values().removeIf(GuildInvite::isExpired);
        });
        invites.entrySet().removeIf(entry -> entry.getValue().isEmpty());
    }
}
