package fr.luc.gamingcore.model;

import java.util.*;

/**
 * Représente un rang personnalisable au sein d'une guilde.
 * Chaque guilde possède ses propres rangs avec une priorité hiérarchique et un ensemble de permissions.
 */
public class GuildRank {

    private final String id;
    private final UUID guildId;
    private String name;
    private int priority;
    private boolean isDefault;
    private final Set<GuildPermission> permissions;

    /**
     * Constructeur d'un rang de guilde.
     *
     * @param id          Identifiant unique du rang (UUID ou clé unique).
     * @param guildId     Identifiant de la guilde propriétaire du rang.
     * @param name        Nom d'affichage du rang (ex: Chef, Officier, Soldat).
     * @param priority    Niveau de priorité hiérarchique (ex: 100 pour le chef, 1 pour recrue).
     * @param isDefault   Indique si ce rang est attribué par défaut aux nouveaux membres.
     * @param permissions Ensemble initial des permissions accordées à ce rang.
     */
    public GuildRank(String id, UUID guildId, String name, int priority, boolean isDefault, Set<GuildPermission> permissions) {
        this.id = Objects.requireNonNull(id, "L'identifiant du rang ne peut pas être nul.");
        this.guildId = Objects.requireNonNull(guildId, "L'identifiant de la guilde ne peut pas être nul.");
        this.name = Objects.requireNonNull(name, "Le nom du rang ne peut pas être nul.");
        this.priority = priority;
        this.isDefault = isDefault;
        this.permissions = permissions != null ? new HashSet<>(permissions) : new HashSet<>();
    }

    /**
     * Obtient l'identifiant unique du rang.
     *
     * @return L'identifiant string du rang.
     */
    public String getId() {
        return id;
    }

    /**
     * Obtient l'identifiant UUID de la guilde à laquelle appartient ce rang.
     *
     * @return L'UUID de la guilde parente.
     */
    public UUID getGuildId() {
        return guildId;
    }

    /**
     * Obtient le nom d'affichage actuel du rang.
     *
     * @return Le nom du rang.
     */
    public String getName() {
        return name;
    }

    /**
     * Définit un nouveau nom d'affichage pour ce rang.
     *
     * @param name Le nouveau nom du rang.
     */
    public void setName(String name) {
        this.name = Objects.requireNonNull(name, "Le nom du rang ne peut pas être nul.");
    }

    /**
     * Obtient le niveau de priorité hiérarchique du rang (plus le chiffre est élevé, plus le pouvoir est grand).
     *
     * @return L'entier de priorité.
     */
    public int getPriority() {
        return priority;
    }

    /**
     * Modifie le niveau de priorité hiérarchique du rang.
     *
     * @param priority La nouvelle valeur de priorité.
     */
    public void setPriority(int priority) {
        this.priority = priority;
    }

    /**
     * Indique si ce rang est le rang attribué par défaut lors de l'intégration d'un nouveau membre.
     *
     * @return true si c'est le rang par défaut, sinon false.
     */
    public boolean isDefault() {
        return isDefault;
    }

    /**
     * Définit si ce rang doit être le rang par défaut pour les nouvelles recrues.
     *
     * @param isDefault Valeur booléenne.
     */
    public void setDefault(boolean isDefault) {
        this.isDefault = isDefault;
    }

    /**
     * Obtient une vue non modifiable de l'ensemble des permissions accordées à ce rang.
     *
     * @return L'ensemble des permissions du rang.
     */
    public Set<GuildPermission> getPermissions() {
        return Collections.unmodifiableSet(permissions);
    }

    /**
     * Vérifie si ce rang possède une permission spécifique.
     *
     * @param permission La permission à vérifier.
     * @return true si le rang possède la permission, false sinon.
     */
    public boolean hasPermission(GuildPermission permission) {
        if (permission == null) return false;
        return permissions.contains(permission);
    }

    /**
     * Ajoute une permission à ce rang.
     *
     * @param permission La permission à accorder.
     * @return true si la permission a été ajoutée, false si elle était déjà présente.
     */
    public boolean addPermission(GuildPermission permission) {
        if (permission == null) return false;
        return permissions.add(permission);
    }

    /**
     * Retire une permission de ce rang.
     *
     * @param permission La permission à révoquer.
     * @return true si la permission a été retirée, false si elle n'était pas présente.
     */
    public boolean removePermission(GuildPermission permission) {
        if (permission == null) return false;
        return permissions.remove(permission);
    }

    /**
     * Définit l'ensemble complet des permissions pour ce rang.
     *
     * @param newPermissions La nouvelle collection de permissions.
     */
    public void setPermissions(Collection<GuildPermission> newPermissions) {
        this.permissions.clear();
        if (newPermissions != null) {
            this.permissions.addAll(newPermissions);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        GuildRank guildRank = (GuildRank) o;
        return Objects.equals(id, guildRank.id) && Objects.equals(guildId, guildRank.guildId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, guildId);
    }
}
