package it.smartcommunitylab.aac.apim;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.springframework.util.CollectionUtils;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import it.smartcommunitylab.aac.model.ClientAppBasic;
import net.minidev.json.JSONObject;

////ignore data from APIM for paramers, we can't properly deserialize it 
//@JsonIgnoreProperties(value = { "parameters" }, allowGetters = true)
public class APIMClient {

    // TODO check with apim
    public static final String SEPARATOR = ",";

    private String clientId;
    private String clientSecret;
    private String clientSecretMobile;
    private String name;
    private String displayName;
    private String redirectUris;
    private Collection<String> grantedTypes;

    private boolean nativeAppsAccess;
    private Map<String, Map<String, Object>> providerConfigurations;
    private String mobileAppSchema;

    private Map<String, Boolean> identityProviders;
    private Map<String, Boolean> identityProviderApproval;

    private String userName;
    private String scope;

    @JsonIgnore
    private Map<String, String> parametersMap;
    private String parameters;

    public APIMClient() {
        this.parametersMap = Collections.emptyMap();
        this.parameters = "";
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public String getClientSecret() {
        return clientSecret;
    }

    public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
    }

    public String getClientSecretMobile() {
        return clientSecretMobile;
    }

    public void setClientSecretMobile(String clientSecretMobile) {
        this.clientSecretMobile = clientSecretMobile;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public String getRedirectUris() {
        return redirectUris;
    }

    public void setRedirectUris(String redirectUris) {
        this.redirectUris = redirectUris;
    }

    public Collection<String> getGrantedTypes() {
        return grantedTypes;
    }

    public void setGrantedTypes(Collection<String> grantedTypes) {
        this.grantedTypes = grantedTypes;
    }

    public boolean isNativeAppsAccess() {
        return nativeAppsAccess;
    }

    public void setNativeAppsAccess(boolean nativeAppsAccess) {
        this.nativeAppsAccess = nativeAppsAccess;
    }

    public Map<String, Map<String, Object>> getProviderConfigurations() {
        return providerConfigurations;
    }

    public void setProviderConfigurations(Map<String, Map<String, Object>> providerConfigurations) {
        this.providerConfigurations = providerConfigurations;
    }

    public String getMobileAppSchema() {
        return mobileAppSchema;
    }

    public void setMobileAppSchema(String mobileAppSchema) {
        this.mobileAppSchema = mobileAppSchema;
    }

    public Map<String, Boolean> getIdentityProviders() {
        return identityProviders;
    }

    public void setIdentityProviders(Map<String, Boolean> identityProviders) {
        this.identityProviders = identityProviders;
    }

    public Map<String, Boolean> getIdentityProviderApproval() {
        return identityProviderApproval;
    }

    public void setIdentityProviderApproval(Map<String, Boolean> identityProviderApproval) {
        this.identityProviderApproval = identityProviderApproval;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

//    public Map<String, String> getParametersMap() {
//        return parametersMap;
//    }
//
//    public void setParametersMap(Map<String, String> parametersMap) {
//        this.parametersMap = parametersMap;
//    }

    public String getParameters() {
        return parameters;
    }

    public void setParameters(String parameters) {
        this.parameters = parameters;
    }

    /*
     * Builders
     */

    public static APIMClient from(ClientAppBasic app) {
        APIMClient client = new APIMClient();
        // base
        client.name = app.getName();
        client.userName = app.getUserName();
        client.displayName = app.getDisplayName();
        // oauth
        client.clientId = app.getClientId();
        client.clientSecret = app.getClientSecret();
        client.grantedTypes = app.getGrantedTypes();
        client.scope = CollectionUtils.isEmpty(app.getScope()) ? ""
                : String.join(SEPARATOR, app.getScope());
        client.redirectUris = CollectionUtils.isEmpty(app.getRedirectUris()) ? ""
                : String.join(SEPARATOR, app.getRedirectUris());
        // deprecated
        client.clientSecretMobile = "";
        client.nativeAppsAccess = false;
        client.mobileAppSchema = app.getMobileAppSchema();

        // apim expects grantTypes in parameters as a string
        Map<String, String> parameters = new HashMap<>();
        parameters.put("grant_types", String.join(SEPARATOR, app.getGrantedTypes()));

        client.parametersMap = parameters;
        // serialize as JSON for apim to understand values..
        client.parameters = JSONObject.toJSONString(parameters);
        return client;
    }

}

@@ -1257,16 +1257,330 @@
 tersMap;
+%0A%0A    // parameters serialized%0A    // something like%0A    // %7B%22tokenScope%22:%22default%22,%0A    // %22validityPeriod%22:%223600%22,%0A    // %22callback_url%22:null,%0A    // %22grant_types%22:%22refresh_token,password,client_credentials,urn:ietf:params:oauth:grant-type:jwt-bearer%22,%0A    // %22key_type%22:%22PRODUCTION%22,%0A    // %22username%22:%22admin%22%7D'
 %0A    pri
@@ -5714,24 +5714,82 @@
 pSchema();%0A%0A
+        Map%3CString, String%3E parameters = new HashMap%3C%3E();%0A
         // a
@@ -5845,35 +5845,147 @@
         
-Map%3CString, S
+parameters.put(%22grant_types%22, String.join(SEPARATOR, app.getGrantedTypes()));%0A        // apim expects subject as username s
 tring
-%3E
+ in
  paramet
@@ -5987,34 +5987,123 @@
 rameters
- = new HashMap%3C%3E
+%0A        // THIS will break since subject != username%0A        parameters.put(%22username%22, app.getUserName
 ()
+)
 ;%0A      
@@ -6108,83 +6108,192 @@
     
-parameters.put(%22grant_types%22, String.join(SEPARATOR, app.getGrantedTypes())
+// additional parameters%0A        parameters.put(%22validityPeriod%22, String.valueOf((int) Math.floor(app.getAccessTokenValidity() / 1000)));%0A        parameters.put(%22tokenScope%22, %22default%22
 );%0A%0A

add additional apim client properties