using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.InformationProtection;

namespace AipGateway.AIP
{
    public class AuthDelegateImplementation : IAuthDelegate
    {
        private static string _clientId = "";
        private static string thumbprint = "";
        private static bool doCertAuth = false;
        private static string _clientSecret = "";


        private ClaimsPrincipal _claimsPrincipal;
                
        public AuthDelegateImplementation(string clientId, string clientSecret, ClaimsPrincipal claimsPrincipal)
        {
            _clientId = clientId;
            _clientSecret = clientSecret;
            _claimsPrincipal = claimsPrincipal;
        }

        public string AcquireToken(Identity identity, string authority, string resource, string claim)
        {
            var authResult = Task.Run(async () => await GetAccessTokenOnBehalfOfUser(authority, resource));
            return authResult.Result;
        }


        public async Task<string> GetAccessTokenOnBehalfOfUser(string authority, string resource)
        {
            IConfidentialClientApplication _app;

            AuthenticationResult result;

            if (doCertAuth)
            {
                // Read X509 cert from local store and build ClientAssertionCertificate.
                X509Certificate2 cert = Utilities.ReadCertificateFromStore(thumbprint);
                
                // Create confidential client using certificate.
                _app = ConfidentialClientApplicationBuilder.Create(_clientId)
                                                .WithRedirectUri(resource)
                                                .WithAuthority(authority)
                                                .WithCertificate(cert)
                                                .Build();                               
            }

            else
            {
                // Create confidential client using client secret.
                _app = ConfidentialClientApplicationBuilder.Create(_clientId)
                                               .WithRedirectUri(resource)
                                               .WithAuthority(authority)
                                               .WithClientSecret(_clientSecret)
                                               .Build();                                
            }

            // Store user access token of authenticated user.
            var ci = (ClaimsIdentity)_claimsPrincipal.Identity;
            string userAccessToken = (string)ci.BootstrapContext;


            // Generate a user assertion with the UPN and access token.            
            UserAssertion userAssertion = new UserAssertion(userAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer");

            // Append .default to the resource passed in to AcquireToken().
            List<string> scopes = new List<string>() { resource[resource.Length - 1].Equals('/') ? $"{resource}.default" : $"{resource}/.default" };

            result = await _app.AcquireTokenOnBehalfOf(scopes, userAssertion)
              .ExecuteAsync();              

            // Return the token to the API caller
            return (result.AccessToken);
        }      
    }
}