package com.github.games647.changeskin.core.shared;

import com.github.games647.changeskin.core.PlatformPlugin;
import com.github.games647.changeskin.core.message.ChannelMessage;
import com.github.games647.changeskin.core.message.CheckPermMessage;
import com.github.games647.changeskin.core.message.PermResultMessage;
import com.github.games647.changeskin.core.message.SkinUpdateMessage;
import com.github.games647.changeskin.core.model.skin.SkinModel;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;

import java.util.UUID;

public abstract class SharedBungeeListener<P> {

    protected final PlatformPlugin<?> plugin;
    protected final String channelName;

    public SharedBungeeListener(PlatformPlugin<?> plugin) {
        this.plugin = plugin;
        this.channelName = plugin.getName();
    }

    protected void handlePayload(P player, byte[] data) {
        ByteArrayDataInput dataInput = ByteStreams.newDataInput(data);
        String subChannel = dataInput.readUTF();

        if ("UpdateSkin".equalsIgnoreCase(subChannel)) {
            updateSkin(dataInput);
        } else if ("PermissionsCheck".equalsIgnoreCase(subChannel)) {
            checkPermissions(player, dataInput);
        }
    }

    private void updateSkin(ByteArrayDataInput dataInput) throws IllegalArgumentException {
        SkinUpdateMessage message = new SkinUpdateMessage();
        message.readFrom(dataInput);

        String playerName = message.getPlayerName();
        P receiver = getPlayerExact(playerName);

        plugin.getLog().info("Instant update for {}", playerName);
        runUpdater(receiver);
    }

    private void checkPermissions(P player, ByteArrayDataInput dataInput) {
        CheckPermMessage message = new CheckPermMessage();
        message.readFrom(dataInput);

        UUID receiverUUID = message.getReceiverUUD();
        boolean op = message.isOp();
        SkinModel targetSkin = message.getTargetSkin();
        UUID skinProfile = targetSkin.getProfileId();

        boolean success = op || checkBungeePerms(player, receiverUUID, skinProfile, message.isSkinPerm());
        sendMessage(player, new PermResultMessage(success, targetSkin, receiverUUID));
    }

    private boolean checkBungeePerms(P player, UUID receiverUUID, UUID targetUUID, boolean skinPerm) {
        String pluginName = plugin.getName().toLowerCase();
        if (getUUID(player).equals(receiverUUID)) {
            boolean hasCommandPerm = hasPermission(player, pluginName + ".command.setskin");
            if (skinPerm) {
                return hasCommandPerm && checkWhitelistPermission(player, targetUUID);
            } else {
                return hasCommandPerm;
            }
        } else {
            boolean hasCommandPerm = hasPermission(player, pluginName + ".command.setskin.other");
            if (skinPerm) {
                return hasCommandPerm && checkWhitelistPermission(player, targetUUID);
            } else {
                return hasCommandPerm;
            }
        }
    }

    protected abstract void sendMessage(P player, String channel, byte[] data);

    protected void sendMessage(P player, ChannelMessage message) {
        ByteArrayDataOutput out = ByteStreams.newDataOutput();
        out.writeUTF(message.getChannelName());

        message.writeTo(out);
        sendMessage(player, channelName, out.toByteArray());
    }

    protected abstract void runUpdater(P receiver);

    protected abstract P getPlayerExact(String name);

    protected abstract UUID getUUID(P player);

    protected abstract boolean hasPermission(P player, String permission);

    protected abstract boolean checkWhitelistPermission(P player, UUID targetUUID);
}

@@ -2141,21 +2141,8 @@
 UID,
- skinProfile,
  mes
@@ -2158,16 +2158,29 @@
 inPerm()
+, skinProfile
 );%0A     
@@ -2338,277 +2338,175 @@
 ID, 
-UUID targetUUID, boolean skinPerm) %7B%0A        String pluginName = plugin.getName().toLowerCase();%0A        if (getUUID(player).equals(receiverUUID)) %7B%0A            boolean hasCommandPerm = hasPermission(player, pluginName + %22.command.setskin%22);%0A            if (skinPerm) %7B
+boolean skinPerm, UUID targetUUID) %7B%0A        if (getUUID(player).equals(receiverUUID)) %7B%0A            return checkPerm(player, %22command.setskin%22, skinPerm, targetUUID);
 %0A   
@@ -2502,32 +2502,35 @@
 tUUID);%0A        
+%7D%0A%0A
         return h
@@ -2532,57 +2532,59 @@
 urn 
-hasCommandPerm && checkWhitelistPermission(play
+checkPerm(player, %22command.setskin.other%22, skinP
 er
+m
 , ta
@@ -2602,99 +2602,162 @@
     
+%7D%0A%0A
     
-    %7D else %7B%0A                return hasCommandPerm;%0A            %7D%0A        %7D else %7B%0A    
+private boolean checkPerm(P invoker, String node, boolean skinPerm, UUID targetUUID) %7B%0A        String pluginName = plugin.getName().toLowerCase();%0A
     
@@ -2795,28 +2795,29 @@
 sPermission(
-play
+invok
 er, pluginNa
@@ -2825,39 +2825,22 @@
 e + 
-%22.command.setskin.other%22);%0A    
+ '.' + node);%0A
     
@@ -2855,28 +2855,24 @@
 skinPerm) %7B%0A
-    
             
@@ -2921,20 +2921,21 @@
 mission(
-play
+invok
 er, targ
@@ -2955,29 +2955,11 @@
     
-    %7D else %7B%0A        
+%7D%0A%0A
     
@@ -2989,32 +2989,8 @@
 rm;%0A
-            %7D%0A        %7D%0A
     

Simplify BungeeCord permissions forwarding