using DataSharing.Share.Dtos.YiBin.Enterprise;
using IdentityModel.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Net.Http.Headers;
using XF.Domain.Cache;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;

namespace DataSharing.YiBin.Enterprise
{
    public class EnterpriseClient : ISingletonDependency, ISelfDependency
    {
        private static readonly string KeyToken = "EnterpriseKeyToken";
        private readonly IServiceScopeFactory _scopeFactory;
        private readonly ILogger<EnterpriseClient> _logger;
        public EnterpriseClient(IServiceScopeFactory scopeFactory, ILogger<EnterpriseClient> logger)
        {
            _scopeFactory = scopeFactory;
            _logger = logger;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="url"></param>
        /// <param name="httpMethod"></param>
        /// <param name="stringContent"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<TResponse?> RequestAsync<TResponse>(string url, string httpMethod, string? stringContent = null, CancellationToken cancellationToken = default)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var sharingConfigurationManager = provider.GetRequiredService<ISharingConfigurationManager>();

            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();
            var cacheToken = provider.GetRequiredService<ITypedCache<TokenTokenEnterpriseInfo>>();

            var token = cacheToken.GetOrSet(KeyToken,
                   d => GetTokenAsync(cancellationToken).GetAwaiter().GetResult(),
                   TimeSpan.FromMinutes(118));
             _logger.LogInformation("请求接口地址：--------------" + url);

            string baseAddress = sharingConfigurationManager.GetYiBinConfig().Enterprise.AddressUrl;
            if (!baseAddress.EndsWith('/'))
                baseAddress += "/";
            return await httpInvoker.RequestStringContentAsync<TResponse>(url, httpMethod, stringContent,
                d => d.SetHttpClient(baseAddress, token), cancellationToken);
        }

        /// <summary>
        /// 获取Token
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="UserFriendlyException"></exception>
        private async Task<TokenTokenEnterpriseInfo> GetTokenAsync(CancellationToken cancellationToken)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var sharingConfigurationManager = provider.GetRequiredService<ISharingConfigurationManager>();
            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();

            var configEnterprise = sharingConfigurationManager.GetYiBinConfig().Enterprise;
            var baseAddress = configEnterprise.AddressUrl;
            if (!baseAddress.EndsWith('/'))
                baseAddress += "/";

            string authorization = configEnterprise.ClientId + ":" + configEnterprise.ClientSecret;
            authorization = Encoder.Base64Code(authorization);
            authorization = authorization.Replace("@", "=");

            var request = new ClientCredentialsTokenRequest
            {
                Address = $"{baseAddress}{YbEnterpriseDefaults.PathToken}",
                Headers =
                {
                    Accept =
                    {
                        MediaTypeWithQualityHeaderValue.Parse("application/json")
                    }
                },
                Method = HttpMethod.Post
            };
            request.Headers.Add("Authorization", "Basic " + authorization);
            request.Headers.Add("Tenant-Id", configEnterprise.TenantId);
            var tokenResponse = await httpInvoker.GetTokenAsync(request, cancellationToken);
            if (tokenResponse is null)
                throw new UserFriendlyException("获取token请求失败");
            if (tokenResponse.IsError)
                throw new UserFriendlyException("获取token请求失败");

             _logger.LogInformation("接口返回，数据解析：--------------" + tokenResponse.Raw);
            var tokenInfo = System.Text.Json.JsonSerializer.Deserialize<TokenEnterprise>(tokenResponse.Raw);
            if (tokenInfo is null || !tokenInfo.Success || tokenInfo?.TokenInfo is null)
                throw new UserFriendlyException("token解析失败");
            return tokenInfo.TokenInfo;
        }

    }
}
