package io.cryptolens.internal;

import com.google.gson.*;
import io.cryptolens.legacy.HttpsURLConnectionRequestHandler;
import io.cryptolens.legacy.RequestHandler;
import io.cryptolens.models.APIError;
import io.cryptolens.models.ErrorType;
import io.cryptolens.models.RequestModel;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class HelperMethods {

    public static <T extends BasicResult> T SendRequestToWebAPI(String method, RequestModel model, Map<String,String> extraParams, Class<T> clazz) {
        return SendRequestToWebAPI(method, model, extraParams, clazz, null);
    }

    public static <T extends BasicResult> T SendRequestToWebAPI(String method, RequestModel model, Map<String,String> extraParams, Class<T> clazz, APIError error) {

        Map<String,String> params = new HashMap<>();
        List<Field> allFields = new ArrayList<>();
        getAllFields(allFields, model.getClass());

        String licenseServerUrl = "https://app.cryptolens.io";

        for(Field field : allFields) {
            field.setAccessible(true);
            try {
                Object value = field.get(model);
                if(value != null) {

                    if(field.getName() == "LicenseServerUrl") {
                        licenseServerUrl = value.toString();
                    } else {
                        params.put(field.getName(), value.toString());
                    }
                }
            } catch (Exception ex) {
                if(error != null) {
                    error.errorType = ErrorType.LibraryError;
                    error.message = ex.getMessage();
                }
            }
        }

        if(extraParams != null)
            params.putAll(extraParams);

        RequestHandler requestHandler = new HttpsURLConnectionRequestHandler();

        try {

            String response = requestHandler.makePostRequest(licenseServerUrl + "/api/" + method, params);

            Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
                @Override
                public LocalDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
                    /*Instant instant = Instant.ofEpochMilli(json.getAsJsonPrimitive().getAsLong());
                    return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()*/
                    return LocalDateTime.parse(json.getAsString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                }
            }).create();

            T res = gson.fromJson(response, clazz);
            res.RawResponse = response;
            return res;

        } catch (Exception ex) {
            if(error != null) {
                error.errorType = ErrorType.LibraryError;
                error.message = ex.toString();
            }
        }

        return  null;
    }

    // from: https://stackoverflow.com/a/1042827/1275924
    private static List<Field> getAllFields(List<Field> fields, Class<?> type) {
        fields.addAll(Arrays.asList(type.getDeclaredFields()));

        if (type.getSuperclass() != null) {
            getAllFields(fields, type.getSuperclass());
        }

        return fields;
    }
}

@@ -274,24 +274,48 @@
 uestModel;%0A%0A
+import javax.net.ssl.*;%0A
 import java.
@@ -361,24 +361,150 @@
 flect.Type;%0A
+import java.security.SecureRandom;%0Aimport java.security.cert.CertificateException;%0Aimport java.security.cert.X509Certificate;%0A
 import java.
@@ -664,24 +664,373 @@
 rMethods %7B%0A%0A
+    /**%0A     * This field can be used to bypass SSL verification when calling app.cryptolens.io. Set this to 'false'%0A     * before calling any of the API methods. Once an API method is called, it will no longer be possible%0A     * to re-enable SSL verification by setting this variable to false.%0A     */%0A    public static boolean SSLEnabled = true;%0A%0A
     public s
@@ -2481,16 +2481,1168 @@
    try %7B
+%0A            if(!HelperMethods.SSLEnabled) %7B%0A                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() %7B%0A                    public boolean verify(String hostname, SSLSession session) %7B%0A                        return true;%0A                    %7D%0A                %7D);%0A                SSLContext context = SSLContext.getInstance(%22TLS%22);%0A                context.init(null, new X509TrustManager%5B%5D%7Bnew X509TrustManager() %7B%0A                    public void checkClientTrusted(X509Certificate%5B%5D chain,%0A                                                   String authType) throws CertificateException %7B%0A                    %7D%0A%0A                    public void checkServerTrusted(X509Certificate%5B%5D chain,%0A                                                   String authType) throws CertificateException %7B%0A                    %7D%0A%0A                    public X509Certificate%5B%5D getAcceptedIssuers() %7B%0A                        return new X509Certificate%5B0%5D;%0A                    %7D%0A                %7D%7D, new SecureRandom());%0A                HttpsURLConnection.setDefaultSSLSocketFactory(%0A                        context.getSocketFactory());%0A            %7D
 %0A%0A      

Add an option to disable SSL verification