using EasyDevCore.Common;
using System.Net.Http.Json;

namespace EasyDevCore.Remote.HttpAccess
{
    /// <summary>
    /// 
    /// </summary>
    public static class HttpClientResponseExtensions
    {
        /// <summary>
        /// Gets the json asynchronous.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="response">The response.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns></returns>
        public static async Task<TResult> GetJsonAsync<TResult>(this Task<HttpResponseMessage> response, TResult defaultValue = default)
        {
            try
            {
                var value = await response;

                if (value.IsSuccessStatusCode)
                {
                    return await value.Content.ReadFromJsonAsync<TResult>();
                }
                else
                {
                    return defaultValue;
                }
            }
            catch
            {
                if (defaultValue != null)
                {
                    return defaultValue;
                }
                throw;
            }
        }

        private static async Task<T> GetValueFromJsonContent<T>(HttpContent content)
        {
            using (var stream = content.ReadAsStreamAsync())
            {
                var result = HttpAccessSetup.JsonSerializerResponse.Deserialize<T>(await stream);
                return result;
            }
        }


        /// <summary>
        /// Makes the result.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="response">The response.</param>
        /// <param name="failure">The failure.</param>
        /// <returns></returns>
        public static async Task<TResult> MakeResultAsync<TResult>(this Task<HttpResponseMessage> response, Func<Exception, TResult> failure = null)
        where TResult : new()
        {
            try
            {
                if (failure == null)
                {
                    failure = (Exception e) => (TResult)Activator.CreateInstance(typeof(TResult), e);
                }
                var value = await response;
                if (value.IsSuccessStatusCode)
                {
                    return await GetValueFromJsonContent<TResult>(value.Content);
                }
                else
                {
                    TResult result = default;
                    string errorMessage = string.Empty;
                    int errorNum = 0;
                    int statusNum = (int)value.StatusCode;
                    try
                    {
                        result = await GetValueFromJsonContent<TResult>(value.Content);
                    }
                    catch
                    {
                        errorMessage = await value.Content.ReadAsStringAsync();
                    }
                    if (result == null)
                    {
                        errorNum = statusNum;
                    }
                    else if (result.GetType().HasInterface(typeof(IValueResult<>)))
                    {
                        bool isError = result.GetPropertyValue<bool>("IsError");
                        if (isError)
                        {
                            string resultCode = result.GetPropertyValue<string>("ResultCode");
                            errorMessage = result.GetPropertyValue<string>("Message");
                            errorNum = int.TryParse(resultCode, out var resultNum) ? resultNum : statusNum;
                        }
                    }
                    Exception exception = new Exception(string.IsNullOrWhiteSpace(errorMessage) ? value.StatusCode.ToString() : errorMessage);
                    exception.HResult = errorNum == 0 ? statusNum : errorNum;
                    return failure(exception);
                }
            }
            catch (Exception ex)
            {
                return failure(ex);
            }
        }
    }
}
