package net.buycraft.plugin.client;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import net.buycraft.plugin.data.RecentPayment;
import net.buycraft.plugin.data.responses.*;
import okhttp3.*;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Objects;

public class ProductionApiClient implements ApiClient {
    private static final String API_URL = "https://plugin.buycraft.net";
    private static final CacheControl NO_STORE = new CacheControl.Builder().noStore().build();

    private final Gson gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .create();
    private final OkHttpClient httpClient;
    private final String secret;

    public ProductionApiClient(String secret) {
        this(secret, new OkHttpClient());
    }

    public ProductionApiClient(String secret, OkHttpClient client) {
        this.secret = Objects.requireNonNull(secret, "secret");
        this.httpClient = Objects.requireNonNull(client, "client");
    }

    private Request.Builder getBuilder(String endpoint) {
        return new Request.Builder()
                .url(API_URL + endpoint)
                .addHeader("X-Buycraft-Secret", secret);
    }

    private <T> T get(String endpoint, Type type) throws IOException, ApiException {
        return get(endpoint, null, type);
    }

    private <T> T get(String endpoint, CacheControl control, Type type) throws IOException, ApiException {
        Request.Builder requestBuilder = getBuilder(endpoint).get();
        if (control != null) requestBuilder.cacheControl(control);
        Request request = requestBuilder.build();

        Response response = httpClient.newCall(request).execute();

        try (ResponseBody body = response.body()) {
            if (response.isSuccessful()) {
                return gson.fromJson(body.charStream(), type);
            } else {
                BuycraftError error = gson.fromJson(body.charStream(), BuycraftError.class);
                if (error != null) {
                    throw new ApiException(error.getErrorMessage());
                } else {
                    throw new ApiException("Unknown error occurred whilst deserializing error object.");
                }
            }
        }
    }

    @Override
    public ServerInformation getServerInformation() throws IOException, ApiException {
        return get("/information", CacheControl.FORCE_NETWORK, ServerInformation.class);
    }

    @Override
    public Listing retrieveListing() throws IOException, ApiException {
        Listing listing = get("/listing", CacheControl.FORCE_NETWORK, Listing.class);
        listing.order();
        return listing;
    }

    @Override
    public QueueInformation retrieveOfflineQueue() throws IOException, ApiException {
        return get("/queue/offline-commands", NO_STORE, QueueInformation.class);
    }

    @Override
    public DueQueueInformation retrieveDueQueue(int limit, int page) throws IOException, ApiException {
        return get("/queue?limit=" + limit + "&page=" + page, CacheControl.FORCE_NETWORK, DueQueueInformation.class);
    }

    @Override
    public QueueInformation getPlayerQueue(int id) throws IOException, ApiException {
        return get("/queue/online-commands/" + id, NO_STORE, QueueInformation.class);
    }

    @Override
    public void deleteCommand(List<Integer> ids) throws IOException, ApiException {
        FormBody.Builder builder = new FormBody.Builder();

        for (Integer id : ids) {
            builder.add("ids[]", id.toString());
        }

        Request request = getBuilder("/queue")
                .method("DELETE", builder.build())
                .build();
        Response response = httpClient.newCall(request).execute();

        if (!response.isSuccessful()) {
            BuycraftError error = gson.fromJson(response.body().charStream(), BuycraftError.class);
            response.body().close();
            throw new ApiException(error.getErrorMessage());
        }
    }

    @Override
    public CheckoutUrlResponse getCheckoutUri(String username, int packageId) throws IOException, ApiException {
        RequestBody body = new FormBody.Builder()
                .add("username", username)
                .add("package_id", Integer.toString(packageId))
                .build();

        Request request = getBuilder("/checkout")
                .post(body)
                .build();
        Response response = httpClient.newCall(request).execute();

        if (!response.isSuccessful()) {
            BuycraftError error = gson.fromJson(response.body().charStream(), BuycraftError.class);
            response.body().close();
            throw new ApiException(error.getErrorMessage());
        } else {
            CheckoutUrlResponse urlResponse = gson.fromJson(response.body().charStream(), CheckoutUrlResponse.class);
            response.body().close();
            return urlResponse;
        }
    }

    @Override
    public List<RecentPayment> getRecentPayments(int limit) throws IOException, ApiException {
        return get("/payments?limit=" + limit, CacheControl.FORCE_NETWORK, new TypeToken<List<RecentPayment>>() {}.getType());
    }
}

@@ -3825,32 +3825,88 @@
 st).execute();%0A%0A
+        try (ResponseBody body = response.body()) %7B%0A    
         if (!res
@@ -3933,32 +3933,36 @@
 ) %7B%0A            
+   
+ 
 BuycraftError er
@@ -3977,39 +3977,28 @@
 on.fromJson(
-response.
 body
-()
 .charStream(
@@ -4030,41 +4030,8 @@
     
-        response.body().close();%0A
     
@@ -4079,32 +4079,46 @@
 rrorMessage());%0A
+            %7D%0A
         %7D%0A    %7D%0A
@@ -4593,32 +4593,91 @@
 st).execute();%0A%0A
+        try (ResponseBody rspBody = response.body()) %7B%0A    
         if (!res
@@ -4692,32 +4692,36 @@
 Successful()) %7B%0A
+    
             Buyc
@@ -4749,38 +4749,30 @@
 n.fromJson(r
-e
 sp
-onse.b
+B
 ody
-()
 .charStream(
@@ -4805,40 +4805,8 @@
     
-       response.body().close();%0A
     
@@ -4804,33 +4804,32 @@
                 
- 
 throw new ApiExc
@@ -4861,32 +4861,36 @@
 age());%0A        
+    
 %7D else %7B%0A       
@@ -4898,41 +4898,18 @@
     
-CheckoutUrlResponse urlResponse =
+    return
  gso
@@ -4920,30 +4920,22 @@
 omJson(r
-e
 sp
-onse.b
+B
 ody
-()
 .charStr
@@ -4985,64 +4985,9 @@
     
-response.body().close();%0A            return urlResponse;
+%7D
 %0A   

Make the non-standard API client functions perform body cleanup