using DataSharing.Province;
using DataSharing.RawData;
using DataSharing.Share.Dtos;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using XF.Domain.Cache;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;

namespace DataSharing.LuZhou.LZCityPortal
{
    public class LZCityPortalSiteClient : ISingletonDependency, ISelfDependency
    {
        private static readonly string KeyToken = "KeyFwToken";
        private readonly IServiceScopeFactory _scopeFactory;
        private readonly IHttpClientFactory _httpClientFactory;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="scopeFactory"></param>
        /// <param name="httpClientFactory"></param>
        public LZCityPortalSiteClient(IServiceScopeFactory scopeFactory, IHttpClientFactory httpClientFactory)
        {
            _scopeFactory = scopeFactory;
            _httpClientFactory = httpClientFactory;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="path"></param>
        /// <param name="httpMethod"></param>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<TResponse> ExecuteAsync<TResponse>(string path, string httpMethod, string request, CancellationToken cancellationToken = default)
        {
            var rsp = string.Empty;
            var client = _httpClientFactory.CreateClient();
            if (HttpMethods.IsGet(httpMethod))
            {
                rsp = await client.GetStringAsync(path, cancellationToken);
            }
            else
            if (HttpMethods.IsPost(httpMethod))
            {
                var dicParam = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(request);
                HttpContent content = new FormUrlEncodedContent(dicParam);
                var response = await client.PostAsync(path, content);
                response.EnsureSuccessStatusCode();
                using var responseContent = response.Content;
                rsp = await responseContent.ReadAsStringAsync(cancellationToken);

            }
            return System.Text.Json.JsonSerializer.Deserialize<TResponse>(rsp);
        }

        /// <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>(DsUserTokenInfo userInfo, 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<GetFwyTokenInfo>>();
            var token = cacheToken.GetOrSet(KeyToken + "_" + userInfo.PlatformSource,
                   d => GetToken(userInfo.AddressUrl, userInfo.AccountId, userInfo.AccountSecret, cancellationToken).GetAwaiter().GetResult(),
                   TimeSpan.FromMinutes(598));
            return await httpInvoker.RequestStringContentAsync<TResponse>(url, httpMethod, stringContent,
                d => d.SetHttpClient(userInfo.AddressUrl, token?.token ?? string.Empty), cancellationToken);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<GetFwyTokenInfo> GetToken(string AddressUrl, string ClientID, string Secret, CancellationToken cancellationToken)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var cacheToken = provider.GetRequiredService<ITypedCache<GetFwyToken>>();
            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();

            var sharingConfigurationManager = provider.GetRequiredService<ISharingConfigurationManager>();

            string url = $"api/v1/Account/api/token?ClientID={ClientID}&Secret={Secret}";

            var baseAddress = AddressUrl;
            if (!baseAddress.EndsWith('/'))
                baseAddress += "/";

            var toke = await httpInvoker.RequestStringContentAsync<GetFwyToken>(baseAddress + url, "Get",
                    null, d => d.SetHttpClient(AddressUrl), cancellationToken);

            if (toke is null || toke.data is null)
                throw new UserFriendlyException("获取token请求失败");
            var dataToken = toke.data;
            if (dataToken is null || string.IsNullOrEmpty(dataToken.token))
                throw new UserFriendlyException("获取token请求失败");

            return dataToken;
        }

        /// <summary>
        /// 请求，不带token
        /// </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?> RequestNoTokenAsync<TResponse>(string url, string httpMethod, string? stringContent = null, CancellationToken cancellationToken = default)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var channelconfigManager = provider.GetRequiredService<IChannelConfigurationManager>();
            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();

            var configHotlineClient = channelconfigManager.GetConfigurationHotlineClient();
            var postUrl = configHotlineClient.AddressUrl + url;
            return await httpInvoker.RequestStringContentAsync<TResponse>(postUrl, httpMethod, stringContent,
                d => d.SetHttpClient(configHotlineClient.AddressUrl), cancellationToken);
        }


        /// <summary>
        /// 请求，不带token
        /// </summary>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="addressUrl"></param>
        /// <param name="url"></param>
        /// <param name="httpMethod"></param>
        /// <param name="stringContent"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<TResponse?> RequestNoTokenOtherAsync<TResponse>(string addressUrl, string url, string httpMethod, string? stringContent = null, CancellationToken cancellationToken = default)
        {
            using var scope = _scopeFactory.CreateScope();
            var provider = scope.ServiceProvider;
            var channelconfigManager = provider.GetRequiredService<IChannelConfigurationManager>();
            var httpInvoker = provider.GetRequiredService<IHttpInvoker>();

            return await httpInvoker.RequestStringContentAsync<TResponse>(addressUrl + url, httpMethod, stringContent,
                d => d.SetHttpClient(addressUrl), cancellationToken);
        }
    }
}
