// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.aad.msal4j;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

class AcquireTokenByAppProviderSupplier extends AuthenticationResultSupplier {

    private AppTokenProviderParameters appTokenProviderParameters;

    private ClientCredentialRequest clientCredentialRequest;

    AcquireTokenByAppProviderSupplier(AbstractClientApplicationBase clientApplication,
                                      ClientCredentialRequest clientCredentialRequest,
                                      AppTokenProviderParameters appTokenProviderParameters) {
        super(clientApplication, clientCredentialRequest);
        this.clientCredentialRequest = clientCredentialRequest;
        this.appTokenProviderParameters = appTokenProviderParameters;
    }

    private static void validateTokenProviderResult(TokenProviderResult tokenProviderResult) {
        if (null == tokenProviderResult.getAccessToken() || tokenProviderResult.getAccessToken().isEmpty()) {
            handleInvalidExternalValueError(tokenProviderResult.getAccessToken());
        }

        if (tokenProviderResult.getExpiresInSeconds() == 0 || tokenProviderResult.getExpiresInSeconds() < 0) {
            handleInvalidExternalValueError(Long.valueOf(tokenProviderResult.getExpiresInSeconds()).toString());
        }

        if (null == tokenProviderResult.getTenantId() || tokenProviderResult.getTenantId().isEmpty()) {
            handleInvalidExternalValueError(tokenProviderResult.getTenantId());
        }
    }

    private static void handleInvalidExternalValueError(String nameOfValue) {
        throw new MsalClientException("The following token provider result value is invalid" + nameOfValue, "Invalid_TokenProviderResult_Input");
    }

    @Override
    AuthenticationResult execute() throws Exception {

        AuthenticationResult authenticationResult = fetchTokenUsingAppTokenProvider(appTokenProviderParameters);

        TokenRequestExecutor tokenRequestExecutor = new TokenRequestExecutor(
                clientCredentialRequest.application().authenticationAuthority,
                msalRequest,
                clientApplication.getServiceBundle()
        );

        clientApplication.tokenCache.saveTokens(tokenRequestExecutor, authenticationResult, clientCredentialRequest.application().authenticationAuthority.host);

        return authenticationResult;
    }

    public AuthenticationResult fetchTokenUsingAppTokenProvider(AppTokenProviderParameters appTokenProviderParameters) throws ExecutionException, InterruptedException {

        CompletableFuture<TokenProviderResult> completableFuture = this.clientCredentialRequest.appTokenProvider.apply(appTokenProviderParameters);

        TokenProviderResult tokenProviderResult = completableFuture.get();

        validateTokenProviderResult(tokenProviderResult);

        return AuthenticationResult.builder()
                .accessToken(tokenProviderResult.getAccessToken())
                .refreshToken(null)
                .idToken(null)
                .expiresOn(tokenProviderResult.getExpiresInSeconds())
                .refreshOn(tokenProviderResult.getRefreshInSeconds())
                .build();

    }
}

@@ -431,16 +431,134 @@
 quest;%0A%0A
+    private static final Logger log = LoggerFactory%0A            .getLogger(AcquireTokenByAppProviderSupplier.class);%0A%0A
     Acqu
@@ -2786,32 +2786,50 @@
 tedException %7B%0A%0A
+        try%7B%0A%0A    
         Completa
@@ -2965,24 +2965,28 @@
 );%0A%0A        
+  
+  
 TokenProvide
@@ -3049,16 +3049,20 @@
         
+    
 validate
@@ -3100,24 +3100,28 @@
 erResult);%0A%0A
+    
         retu
@@ -3170,16 +3170,20 @@
         
+    
 .accessT
@@ -3233,32 +3233,36 @@
                 
+    
 .refreshToken(nu
@@ -3281,16 +3281,20 @@
         
+  
+  
 .idToken
@@ -3292,32 +3292,36 @@
  .idToken(null)%0A
+    
                 
@@ -3366,32 +3366,36 @@
 resInSeconds())%0A
+    
                 
@@ -3464,16 +3464,20 @@
         
+    
 .build()
@@ -3474,21 +3474,127 @@
   .build();%0A
+        %7D catch (Exception ex)%7B%0A            log.debug(ex.getMessage());%0A            return null;%0A        %7D
 %0A    %7D%0A%7D%0A

Change log level to debug for appTokenProvider