using DataSharing.Share.Dtos.Province;
using IdentityModel.Client;
using Microsoft.Extensions.DependencyInjection;
using System.Net.Http.Headers;
using XF.Domain.Cache;
using XF.Domain.Exceptions;

namespace DataSharing.Province
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class ProvinceClient
    {
        private static readonly string KeyToken = "KeyToken";
        private readonly IServiceScopeFactory _scopeFactory;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="scopeFactory"></param>
        public ProvinceClient(IServiceScopeFactory scopeFactory)
        {
            _scopeFactory = scopeFactory;
        }

        public async Task<TResponse?> RequestAsync<TRequest, TResponse>(
            TRequest request,
            string baseAddress,
            ConfigurationProvince configProvince,
            CancellationToken cancellationToken)
            where TRequest : IProvinceRequest, new()
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();
            var cacheToken = provider.GetRequiredService<ITypedCache<TokenInfo>>();

            //不同的批次获取TOKEN的地址不一样
            string cacheKey = "";
            if (baseAddress == configProvince.HuiJu)
                cacheKey = KeyToken + "_HuiJu";
            else
                cacheKey = KeyToken + "_XieTong";

            var token = cacheToken.GetOrSet(cacheKey,
                d => GetTokenAsync(baseAddress, cancellationToken).GetAwaiter().GetResult(),
                TimeSpan.FromMinutes(28));
            //var configProvince = channelconfigManager.GetConfigurationProvince();
            request.BuildClientInfo(configProvince.ClientId, configProvince.ClientSecret);

            //todo token失效重新获取token再次请求，返回参数缺少该状态，暂无法处理

            return await httpInvoker.RequestAsync<TRequest, TResponse>(request,
                d => d.SetHttpClient(baseAddress, token?.AccessToken ?? string.Empty),
                cancellationToken);
        }

        public async Task<TResponse?> RequestAsync<TResponse>(
            string baseAddress,
            ConfigurationProvince configProvince,
            string url,
            string httpMethod,
            //  IHttpInvoker httpInvoker,
            //  ITypedCache<TokenInfo> cacheToken,
            string? stringContent = null,
            CancellationToken cancellationToken = default)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();
            var cacheToken = provider.GetRequiredService<ITypedCache<TokenInfo>>();

            //不同的批次获取TOKEN的地址不一样
            string cacheKey = "";
            if (baseAddress == configProvince.HuiJu)
                cacheKey = KeyToken + "_HuiJu";
            else
                cacheKey = KeyToken + "_XieTong";

            var token = cacheToken.GetOrSet(cacheKey,
                d => GetTokenAsync(baseAddress, cancellationToken).GetAwaiter().GetResult(),
                TimeSpan.FromMinutes(28));

            //todo token失效重新获取token再次请求，返回参数缺少该状态，暂无法处理

            return await httpInvoker.RequestStringContentAsync<TResponse>(url, httpMethod, stringContent,
                d => d.SetHttpClient(baseAddress, token?.AccessToken ?? string.Empty), cancellationToken);
        }

        /// <summary>
        /// 附件获取Token
        /// </summary>
        /// <param name="baseAddress"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<TokenInfo> GetToken(string baseAddress, CancellationToken cancellationToken)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var cacheToken = provider.GetRequiredService<ITypedCache<TokenInfo>>();
            string cacheKey = KeyToken + "_HuiJu";

            var token = cacheToken.GetOrSet(cacheKey,
                d => GetTokenAsync(baseAddress, cancellationToken).GetAwaiter().GetResult(),
                TimeSpan.FromMinutes(28));
            return token;
        }

        /// <summary>
        /// 获取token
        /// </summary>
        /// <param name="baseAddress"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="UserFriendlyException"></exception>
        public async Task<TokenInfo> GetTokenAsync(string baseAddress, CancellationToken cancellationToken)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var channelconfigManager = provider.GetRequiredService<IChannelConfigurationManager>();
            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();

            var configProvince = channelconfigManager.GetConfigurationProvince();
            if (!baseAddress.EndsWith('/'))
                baseAddress += "/";

            //获取秘钥，默认为汇聚的
            var clientId = configProvince.ClientId;
            var clientSecret = configProvince.ClientSecret;

            //如果是协同的，取协同数据
            if (baseAddress == configProvince.XieTong)
            {
                clientId = configProvince.ClientIdXieTong;
                clientSecret = configProvince.ClientSecretXieTong;
            }

            var request = new ClientCredentialsTokenRequest
            {
                ClientId = clientId,
                ClientSecret = clientSecret,
                Address = $"{baseAddress}oauth2/token",
                Headers =
                {
                    Accept =
                    {
                        MediaTypeWithQualityHeaderValue.Parse("application/x-www-form-urlencoded")
                    }
                }

            };
            var tokenResponse = await httpInvoker.GetTokenAsync(request, cancellationToken);
            if (tokenResponse is null)
                throw new UserFriendlyException("获取token请求失败");
            if (tokenResponse.IsError)
                throw new UserFriendlyException("获取token请求失败：" + tokenResponse.Error);

            var tokenInfo = System.Text.Json.JsonSerializer.Deserialize<TokenRsp>(tokenResponse.Raw);
            if (tokenInfo?.TokenInfo is null)
                throw new UserFriendlyException("token解析失败");
            return tokenInfo.TokenInfo;
        }
    }
}
