package me.minidigger.voxelgameslib.user;

import com.google.gson.annotations.Expose;

import net.kyori.text.Component;
import net.kyori.text.TextComponent;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.inject.Inject;

import me.minidigger.voxelgameslib.chat.ChatChannel;
import me.minidigger.voxelgameslib.chat.ChatHandler;
import me.minidigger.voxelgameslib.config.GlobalConfig;
import me.minidigger.voxelgameslib.game.GameMode;
import me.minidigger.voxelgameslib.lang.Locale;
import me.minidigger.voxelgameslib.persistence.PersistenceHandler;
import me.minidigger.voxelgameslib.role.Permission;
import me.minidigger.voxelgameslib.role.Role;
import me.minidigger.voxelgameslib.utils.ChatUtil;

import org.bukkit.entity.Player;

import jskills.Rating;

/**
 * abstract implementation of the user interface that deals with some stuff
 */
public class GamePlayer implements User {

    @Inject
    private GlobalConfig config;
    @Inject
    private PersistenceHandler persistenceHandler;
    @Inject
    private ChatHandler chatHandler;

    private Player player;

    @Expose
    private UUID uuid;

    @Expose
    private Role role = Role.DEFAULT;

    @Expose
    private Locale locale = Locale.ENGLISH;

    @Expose
    private Map<String, Rating> ratings = new HashMap<>();

    // combination of <prefix> <rawdisplayname> <suffix>
    private Component displayName;

    @Expose
    private String rawDisplayName;

    @Expose
    private Component prefix = new TextComponent("");
    @Expose
    private Component suffix = new TextComponent("");

    @Expose
    private List<ChatChannel> channels;
    @Expose
    private ChatChannel activeChannel;

    @Nonnull
    @Override
    public UUID getUuid() {
        return uuid;
    }

    @Override
    public void sendMessage(@Nonnull Component message) {
        ChatUtil.sendMessage(this, message);
    }

    @Override
    public boolean hasPermission(@Nonnull Permission perm) {
        if (config.useRoleSystem) {
            return getRole().hasPermission(perm);
        }
        return getPlayer().hasPermission(perm.getString());
    }

    @Override
    public Component getDisplayName() {
        if (displayName == null) {
            displayName = prefix.copy().append(new TextComponent(rawDisplayName)).append(suffix);
        }
        return displayName;
    }

    @Override
    public String getRawDisplayName() {
        return rawDisplayName;
    }

    @Override
    public Player getPlayer() {
        return player;
    }

    @Override
    public Locale getLocale() {
        return locale;
    }

    @Override
    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    @Override
    public Role getRole() {
        return role;
    }

    @Override
    public void setRole(Role role) {
        this.role = role;
    }

    @Override
    public Rating getRating(GameMode mode) {
        Rating rating = ratings.get(mode.getName());
        if (rating == null) {
            rating = mode.getDefaultRating();
            // no need to save here
        }
        return rating;
    }

    @Override
    public void saveRating(GameMode mode, Rating rating) {
        ratings.put(mode.getName(), rating);
        persistenceHandler.getProvider().saveUser(this);
    }

    @Override
    public Map<String, Rating> getRatings() {
        return ratings;
    }

    @Override
    public void setPlayer(Player player) {
        this.player = player;
    }

    @Override
    public void setDisplayName(String displayName) {
        this.rawDisplayName = displayName;
        this.displayName = null; // regenerate full display name
    }

    @Override
    public double getPartialPlayPercentage() {
        return 1.0;
    }

    @Override
    public double getPartialUpdatePercentage() {
        return 1.0;
    }

    @Override
    public Component getPrefix() {
        return prefix;
    }

    @Override
    public Component getSuffix() {
        return suffix;
    }

    @Override
    public void setPrefix(Component prefix) {
        this.prefix = prefix;
    }

    @Override
    public void setSuffix(Component suffix) {
        this.suffix = suffix;
    }

    @Override
    public void setUuid(UUID uuid) {
        this.uuid = uuid;
    }

    @Override
    public List<ChatChannel> getChannels() {
        return channels;
    }

    @Override
    public void addListeningChannel(String identifier) {
        ChatChannel channel = chatHandler.getChannel(identifier).isPresent() ? chatHandler.getChannel(identifier).get() : null;

        if (channel != null) {
            channels.add(channel);
            channel.addListener(this);
        }
    }

    @Override
    public void removeListeningChannel(String identifier) {
        ChatChannel channel = chatHandler.getChannel(identifier).isPresent() ? chatHandler.getChannel(identifier).get() : null;

        if (channel != null) {
            channels.remove(channel);
            channel.removeListener(this);

            if (channel == activeChannel) {
                activeChannel = chatHandler.defaultChannel;
            }
        }
    }

    @Override
    public ChatChannel getActiveChannel() {
        return activeChannel;
    }

    @Override
    public void setActiveChannel(String identifier) {
        ChatChannel channel = chatHandler.getChannel(identifier).isPresent() ? chatHandler.getChannel(identifier).get() : null;

        if (channel != null) {
            activeChannel = channel;
        }
    }
}

@@ -147,24 +147,52 @@
 Component;%0A%0A
+import java.util.ArrayList;%0A
 import java.
@@ -246,24 +246,51 @@
 a.util.Map;%0A
+import java.util.Optional;%0A
 import java.
@@ -1746,24 +1746,44 @@
 el%3E channels
+ = new ArrayList%3C%3E()
 ;%0A    @Expos
@@ -4582,32 +4582,41 @@
 fier) %7B%0A        
+Optional%3C
 ChatChannel chan
@@ -4602,32 +4602,33 @@
 onal%3CChatChannel
+%3E
  channel = chatH
@@ -4660,70 +4660,8 @@
 ier)
-.isPresent() ? chatHandler.getChannel(identifier).get() : null
 ;%0A%0A 
@@ -4674,32 +4674,36 @@
  if (channel
- != null
+.isPresent()
 ) %7B%0A        
@@ -4718,32 +4718,38 @@
 nels.add(channel
+.get()
 );%0A            c
@@ -4755,16 +4755,22 @@
 channel.
+get().
 addListe

fix chat