package com.voxelmodpack.hdskins.skins;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.gson.JsonObject;
import com.google.gson.annotations.Expose;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
import com.mojang.util.UUIDTypeAdapter;
import com.voxelmodpack.hdskins.HDSkinManager;
import net.minecraft.util.Session;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.io.IOException;
import java.net.URI;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import javax.annotation.Nullable;

@ServerType("bethlehem")
public class BethlehemSkinServer implements SkinServer {

    private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";

    @Expose
    private final String address;

    private BethlehemSkinServer(String address) {
        this.address = address;
    }

    @Override
    public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException {
        try (MoreHttpResponses response = new NetClient("GET", getPath(profile)).send()) {

            JsonObject s = response.json(JsonObject.class);

            if (s.has("success") && s.get("success").getAsBoolean()) {
                s = s.get("data").getAsJsonObject();
                return gson.fromJson(s, MinecraftTexturesPayload.class);
            }
            throw new IOException(s.get("error").getAsString());
        }
    }

    @Override
    public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, SkinUpload skin) {
        URI image = skin.getImage();
        Map<String, String> metadata = skin.getMetadata();
        MinecraftProfileTexture.Type type = skin.getType();
        return CallableFutures.asyncFailableFuture(() -> {
            SkinServer.verifyServerConnection(session, SERVER_ID);

            NetClient client = new NetClient("POST", address).putHeaders(createHeaders(session, type, image, metadata));

            if (image != null) {
                client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
            }

            try (MoreHttpResponses response = client.send()) {
                if (!response.ok()) {
                    throw new IOException(response.text());
                }
                return new SkinUploadResponse(response.text());
            }

        }, HDSkinManager.skinUploadExecutor);
    }

    protected Map<String, ?> createHeaders(Session session, Type type, @Nullable URI image, Map<String, String> metadata) {
        Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
                .put("accessToken", session.getToken())
                .put("user", session.getUsername())
                .put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId()))
                .put("type", type.toString().toLowerCase(Locale.US));

        if (image == null) {
            builder.put("clear", "1");
        } else {
            builder.put("model", metadata.getOrDefault("mode", "default"));
        }

        return builder.build();
    }

    private String getPath(GameProfile profile) {
        return String.format("%s/profile/%s", address, UUIDTypeAdapter.fromUUID(profile.getId()));
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)
                .append("address", address)
                .build();
    }
}

@@ -140,43 +140,8 @@
 er;%0A
-import com.google.gson.JsonObject;%0A
 impo
@@ -222,135 +222,8 @@
 le;%0A
-import com.mojang.authlib.minecraft.MinecraftProfileTexture;%0Aimport com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;%0A
 impo
@@ -501,29 +501,8 @@
 on;%0A
-import java.net.URI;%0A
 impo
@@ -596,43 +596,8 @@
 e;%0A%0A
-import javax.annotation.Nullable;%0A%0A
 @Ser
@@ -1116,178 +1116,124 @@
     
-JsonObject s = response.json(JsonObject.class);%0A%0A            if (s.has(%22success%22) && s.get(%22success%22).getAsBoolean()) %7B%0A                s = s.get(%22data%22).getAsJsonObject(
+if (!response.ok()) %7B%0A                throw new IOException(response.getResponse().getStatusLine().getReasonPhrase()
 );%0A 
@@ -1244,39 +1244,47 @@
     
+   %7D%0A%0A
        
+     
 return 
-gson.fromJ
+response.j
 son(
-s, 
 Mine
@@ -1316,87 +1316,8 @@
 s);%0A
-            %7D%0A            throw new IOException(s.get(%22error%22).getAsString());%0A
     
@@ -1435,171 +1435,17 @@
 oad 
-skin) %7B%0A        URI image = skin.getImage();%0A        Map%3CString, String%3E metadata = skin.getMetadata();%0A        MinecraftProfileTexture.Type type = skin.getType();
+upload) %7B
 %0A   
@@ -1564,24 +1564,54 @@
 ERVER_ID);%0A%0A
+            // TODO: Fix this%0A
             
@@ -1659,16 +1659,37 @@
 address)
+;%0A%0A            client
 .putHead
@@ -1719,29 +1719,14 @@
 on, 
-type, image, metadata
+upload
 ));%0A
@@ -1742,21 +1742,33 @@
     if (
-i
+upload.getI
 mage
+()
  != null
@@ -1802,20 +1802,32 @@
 putFile(
-t
+upload.getT
 ype
+()
 .toStrin
@@ -1867,21 +1867,33 @@
 e/png%22, 
-i
+upload.getI
 mage
+()
 );%0A     
@@ -2277,68 +2277,25 @@
 on, 
-Type type, @Nullable URI image, Map%3CString, String%3E metadata
+SkinUpload upload
 ) %7B%0A
@@ -2597,20 +2597,32 @@
 %22type%22, 
-t
+upload.getT
 ype
+()
 .toStrin
@@ -2663,21 +2663,33 @@
     if (
-i
+upload.getI
 mage
+()
  == null
@@ -2785,16 +2785,28 @@
 l%22, 
-m
+upload.getM
 etadata
+()
 .get

Fix and update error handling for bethlehem