using System.Net;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using Long.Core.Api;
using Long.Core.Extensions;
using Long.Utils.Cache;

namespace Long.Utils.Network;

/// <summary>
/// 网络请求类
/// </summary>
public static class Request
{
    private static readonly string _ObjectCachingkey = "Long.Utils.Request.Authorization";

    /// <summary>
    /// 设置认证信息
    /// </summary>
    /// <param name="authorization"></param>
    /// <returns></returns>
    public static async Task SetAuthorization(LongToken token)
    {
        if (ObjectCaching.Contains(_ObjectCachingkey))
        {
            ObjectCaching.Remove(_ObjectCachingkey);
        }
        ObjectCaching.Add(_ObjectCachingkey, token);
    }

    /// <summary>
    /// 请求数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url"></param>
    /// <param name="isToken"> 是否使用 token，默认 true</param>
    /// <returns></returns>
    public static async Task<RequestResult<T>> GetAsync<T>(string url, bool isToken = true)
    {
        return await GetAsync<T>(url, null, isToken);
    }

    /// <summary>
    /// 请求数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url"></param>
    /// <param name="param">请求参数</param>
    /// <param name="isToken"> 是否使用 token，默认 true</param>
    /// <returns></returns>
    public static async Task<RequestResult<T>> GetAsync<T>(string url, object param, bool isToken = true)
    {
        var result = new RequestResult<T>();
        try
        {
            var paramStr = "";
            bool hasUrlParam = url.IndexOf("?") > -1;
            if (param != null)
            {
                Type type = param.GetType();
                foreach (var item in type.GetProperties())
                {
                    if (hasUrlParam)
                    {
                        paramStr += "&";
                    }
                    else
                    {
                        hasUrlParam = true;
                        paramStr += "?";
                    }
                    paramStr += item.Name + "=" + item.GetValue(param).ToString();
                }
                url += paramStr;
            }
            HttpClient client = null;
            if (isToken)
            {
                client = GetTokenHttpClient();
            }
            else
            {
                client = GetHttpClient();
            }
            var httpResponse = await client.GetAsync(url);
            var bytes = await httpResponse.Content.ReadAsByteArrayAsync();
            result.StatusCode = httpResponse.StatusCode;
            var decodeStr = Encoding.UTF8.GetString(bytes);
            if (decodeStr.IsXML() && decodeStr.IndexOf("meta charset=\"gb2312\"") > 0)
            {
                decodeStr = Encoding.GetEncoding("gb2312").GetString(bytes);
            }
            if (httpResponse.StatusCode == HttpStatusCode.OK)
            {
                var res = decodeStr.IsJSON() ? JsonSerializer.Deserialize<ApiResult<T>>(decodeStr) : new ApiResult<T>()
                {
                    Success = false,
                    Result = default(T),
                    Message = ""
                };
                if (res.Success)
                {
                    result.Success = true;
                    result.Result = res.Result;
                }
                else
                {
                    result.Success = false;
                    result.Message = res.Message;
                }
            }
            else
            {
                result.Success = false;
                result.Result = default(T);
                result.Message = decodeStr;
            }
        }
        catch (Exception ex)
        {
            result.Success = false;
            result.Result = default(T);
            result.Message = ex.Message;
        }
        return result;
    }

    public static async Task<RequestResult<string>> GetAsync(string url, bool isToken = true)
    {
        return await GetAsync(url, null, isToken);
    }

    public static async Task<RequestResult<string>> GetAsync(string url, object param, bool isToken = true)
    {
        var result = new RequestResult<string>();
        try
        {
            var paramStr = "";
            bool hasUrlParam = url.IndexOf("?") > -1;
            if (param != null)
            {
                Type type = param.GetType();
                foreach (var item in type.GetProperties())
                {
                    if (hasUrlParam)
                    {
                        paramStr += "&";
                    }
                    else
                    {
                        hasUrlParam = true;
                        paramStr += "?";
                    }
                    paramStr += item.Name + "=" + item.GetValue(param).ToString();
                }
                url += paramStr;
            }
            HttpClient client = null;
            if (isToken)
            {
                client = GetTokenHttpClient();
            }
            else
            {
                client = GetHttpClient();
            }
            var httpResponse = await client.GetAsync(url);
            var bytes = await httpResponse.Content.ReadAsByteArrayAsync();
            result.StatusCode = httpResponse.StatusCode;
            var decodeStr = Encoding.UTF8.GetString(bytes);
            if (decodeStr.IsXML() && decodeStr.IndexOf("meta charset=\"gb2312\"") > 0)
            {
                decodeStr = Encoding.GetEncoding("gb2312").GetString(bytes);
            }
            if (httpResponse.StatusCode == HttpStatusCode.OK)
            {
                result.Success = true;
                result.Result = decodeStr;
            }
            else
            {
                result.Success = false;
                result.Message = decodeStr;
            }
        }
        catch (Exception ex)
        {
            result.Success = false;
            result.Message = ex.Message;
        }
        return result;
    }

    /// <summary>
    /// 发送数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url"></param>
    /// <param name="isToken"></param>
    /// <returns></returns>
    public static async Task<RequestResult<T>> PostAsync<T>(string url, bool isToken = true)
    {
        return await PostAsync<T>(null, url, isToken);
    }

    public static async Task<RequestResult<T>> PostAsync<T>(HttpContent httpContent, string url, bool isToken = true)
    {
        var result = new RequestResult<T>();
        HttpClient client = null;
        try
        {
            if (isToken)
            {
                client = GetTokenHttpClient();
            }
            else
            {
                client = GetHttpClient();
            }
            if (httpContent == null)
            {
                httpContent = new StringContent("");
            }
            var httpResponse = await client.PostAsync(url, httpContent);
            var bytes = await httpResponse.Content.ReadAsByteArrayAsync();
            result.StatusCode = httpResponse.StatusCode;

            var decodeStr = Encoding.UTF8.GetString(bytes);
            if (decodeStr.IsXML() && decodeStr.IndexOf("meta charset=\"gb2312\"") > 0)
            {
                decodeStr = Encoding.GetEncoding("gb2312").GetString(bytes);
            }
            if (httpResponse.StatusCode == HttpStatusCode.OK)
            {
                var res = decodeStr.IsJSON() ? JsonSerializer.Deserialize<ApiResult<T>>(decodeStr) : new ApiResult<T>()
                {
                    Success = false,
                    Result = default(T),
                    Message = ""
                };
                if (res.Success)
                {
                    result.Success = true;
                    result.Result = res.Result;
                }
                else
                {
                    result.Success = false;
                    result.Message = res.Message;
                }
            }
            else
            {
                result.Success = false;
                result.Result = default(T);
                result.Message = decodeStr;
            }
        }
        catch (Exception ex)
        {
            result.Success = false;
            result.Result = default(T);
            result.Message = ex.Message.IndexOf("Timeout of") > 0 ? "" : ex.Message;
        }
        return result;
    }

    public static async Task<RequestResult<string>> PostAsync(string url, bool isToken = true)
    {
        return await PostAsync(url, null, isToken);
    }

    public static async Task<RequestResult<string>> PostAsync(HttpContent httpContent, string url, bool isToken = true)
    {
        var result = new RequestResult<string>();
        HttpClient client = null;
        try
        {
            if (isToken)
            {
                client = GetTokenHttpClient();
            }
            else
            {
                client = GetHttpClient();
            }
            if (httpContent == null)
            {
                httpContent = new StringContent("");
            }
            var httpResponse = await client.PostAsync(url, httpContent);
            var bytes = await httpResponse.Content.ReadAsByteArrayAsync();
            result.StatusCode = httpResponse.StatusCode;

            var decodeStr = Encoding.UTF8.GetString(bytes);
            if (decodeStr.IsXML() && decodeStr.IndexOf("meta charset=\"gb2312\"") > 0)
            {
                decodeStr = Encoding.GetEncoding("gb2312").GetString(bytes);
            }
            if (httpResponse.StatusCode == HttpStatusCode.OK)
            {
                result.Success = true;
                result.Result = decodeStr;
            }
            else
            {
                result.Success = false;
                result.Message = decodeStr;
            }
        }
        catch (Exception ex)
        {
            result.Success = false;
            result.Message = ex.Message.IndexOf("Timeout of") > 0 ? "" : ex.Message;
        }
        return result;
    }

    /// <summary>
    /// 发送数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url"></param>
    /// <param name="data"></param>
    /// <param name="isToken"> 是否使用 token，默认 true</param>
    /// <returns></returns>
    public static async Task<RequestResult<T>> PostAsync<T>(string url, object data, bool isToken = true)
    {
        var content = Request.GetStringContent(data, Encoding.UTF8, "text/json");
        return await Request.PostAsync<T>(content, url, isToken);
    }

    /// <summary>
    /// 发送数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url"></param>
    /// <param name="data"></param>
    /// <param name="isToken"> 是否使用 token，默认 true</param>
    /// <returns></returns>
    public static async Task<RequestResult<string>> PostAsync(string url, object data, bool isToken = true)
    {
        var content = Request.GetStringContent(data, Encoding.UTF8, "text/json");
        return await Request.PostAsync(content, url, isToken);
    }

    public static async Task<RequestResult<T>> PostFormUrlEncodedAsync<T>(string url, object data, bool isToken = true)
    {
        var content = Request.GetFormUrlEncodedContent(data);
        return await Request.PostAsync<T>(content, url, isToken);
    }

    /// <summary>
    /// 获取 HttpClient 对象
    /// </summary>
    /// <returns></returns>
    public static HttpClient GetHttpClient()
    {
        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Add("KeepAlive", "false");
        return client;
    }

    /// <summary>
    /// 获取带 Token 的 HttpClient 对象
    /// </summary>
    /// <returns></returns>
    public static HttpClient GetTokenHttpClient()
    {
        HttpClient client = GetHttpClient();
        var token = ObjectCaching.Get<LongToken>(_ObjectCachingkey);
        if (token != null)
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token.token_type, token.access_token);
        }
        return client;
    }

    public static StringContent GetStringContent(object data, Encoding encoding, string type)
    {
        var dataStr = JsonSerializer.Serialize(data);
        return new StringContent(dataStr, encoding, type);
    }

    public static FormUrlEncodedContent GetFormUrlEncodedContent(object data)
    {
        var result = new List<KeyValuePair<string, string>>();
        var type = data.GetType();
        foreach (var item in type.GetProperties())
        {
            string value = item.GetValue(data)?.ToString() ?? "";
            result.Add(new KeyValuePair<string, string>(item.Name, value));
        }
        return new FormUrlEncodedContent(result);
    }

    public static MultipartFormDataContent GetMultipartFormDataContent(object data)
    {
        var result = new MultipartFormDataContent();
        result.Add(Request.GetFormUrlEncodedContent(data));
        return result;
    }
}

/// <summary>
/// 网络请求结果类
/// </summary>
/// <typeparam name="T"></typeparam>
public class RequestResult<T>
{
    public T Result { get; set; }
    public bool Success { get; set; }
    public string Message { get; set; }
    public HttpStatusCode StatusCode { get; set; }
}
