using CrazyStudio.Core.Common;
using CrazyStudio.Core.Common.Eitities;
using Microsoft.AspNetCore.DataProtection;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Web;
using XPrintServer.Api.Entities.Vol;


namespace XPrintServer.Api.Tools
{
    public class RequestInfo
    {
        public string Url { get; set; } = "";
        public string Version { get; set; } = "";
        public string Action { get; set; } = "";
        public string ServiceName { get; set; } = "";
        public string Region { get; set; } = "";
        public object Data { get; set; } = null!;

        public string Method { get; set; } = "POST";
        public Action<Exception> Fail { get; set; } = (error) => { };
    }

    public class HttpVolTool
    {
        /// <summary>
        /// 不参与加签过程的 header key
        /// </summary>
        private static readonly HashSet<string> HEADER_KEYS_TO_IGNORE = new HashSet<string>
        {
            "authorization",
            "content-type",
            "content-length",
            "user-agent",
            "presigned-expires",
            "expect"
        };

        ///// <summary>
        ///// 测试Get请求
        ///// </summary>
        //private void TestGet()
        //{
        //    string temp = "HMAC-SHA256 Credential=AKLTYWViMTVmZGYzM2E0NDI5Mzk2MDZjNjFmMjc2MjRjMzg/20250329/cn-beijing/billing/request, SignedHeaders=host;x-date, Signature=1eda9e7e6b1728151a8e8791fdaf67cfbd28bd5c80d0fce2eb208746cf483105";

        //    string HTTPRequestMethod = "GET";
        //    var CanonicalQueryString = new Dictionary<string, string>
        //{
        //    { "Version", "2022-01-01" },
        //    { "Action", "QueryBalanceAcct" }
        //};
        //    var Headers = new Dictionary<string, string>
        //{
        //    { "host", "billing.volcengineapi.com" },
        //    { "x-date", "20250329T180937Z" }
        //};
        //    string RequestPayload = "";
        //    //地域
        //    string region = "cn-beijing";

        //    string result = Sign(HTTPRequestMethod, CanonicalQueryString, Headers, RequestPayload, AccessKeyID, SecretAccessKey, region);
        //    if (temp == result)
        //    {
        //        Debug.Log("Get ok");
        //    }
        //}


        ///// <summary>
        ///// 测试Post请求
        ///// </summary>
        //private void TestPost()
        //{
        //    string temp = "HMAC-SHA256 Credential=AKLTYWViMTVmZGYzM2E0NDI5Mzk2MDZjNjFmMjc2MjRjMzg/20250329/cn-beijing/billing/request, SignedHeaders=host;x-date, Signature=5e8480ceea12d0000a23c054151c50dd02c1a7dec835004057d19f13d53a7658";

        //    string HTTPRequestMethod = "POST";
        //    var CanonicalQueryString = new Dictionary<string, string> { { "Version", "2022-01-01" }, { "Action", "ListBill" } };
        //    var Headers = new Dictionary<string, string> { { "host", "billing.volcengineapi.com" }, { "x-date", "20250329T180937Z" } };
        //    var obj = new { Limit = 10, BillPeriod = "2023-08" };
        //    string RequestPayload = JsonSerializer.Serialize(obj);
        //    //地域
        //    string region = "cn-beijing";

        //    string result = Sign(HTTPRequestMethod, CanonicalQueryString, Headers, RequestPayload, AccessKeyID, SecretAccessKey, region);
        //    if (temp == result)
        //    {
        //        Debug.WriteLine("Post ok");
        //    }
        //}

        /// <summary>
        /// 火山引擎API调用
        /// </summary>
        public static async Task<T?> RequestVol<T>(RequestInfo requestInfo, VolInfos volInfos)
        {
            var canonicalQueryString = new Dictionary<string, string> { { "Version", requestInfo.Version }, { "Action", requestInfo.Action } };
            var headers = new Dictionary<string, string> { { "host", requestInfo.Url.Replace("https://", "") }, { "x-date", GetDateTimeNow() } };
            string requestPayload = JsonSerializer.Serialize(requestInfo.Data);


            var authorization = Sign(requestInfo.Method, requestInfo.ServiceName, canonicalQueryString, headers, requestPayload, volInfos.AccessKeyId, volInfos.SecretAccessKey, requestInfo.Region);

            var queryString = string.Join("&", canonicalQueryString
                .Where(kv => kv.Value != null)
                .Select(kv => $"{UriEscape(kv.Key)}={UriEscape(kv.Value)}"));

            var client = new HttpClient();
            var request = new HttpRequestMessage
            {
                Method = new HttpMethod(requestInfo.Method),
                RequestUri = new Uri($"{requestInfo.Url}?{queryString}"),
                Content = new StringContent(JsonSerializer.Serialize(requestInfo.Data),
                                          Encoding.UTF8, "application/json")
            };

            foreach (var header in headers)
            {
                request.Headers.Add(header.Key, header.Value);
            }
            request.Headers.TryAddWithoutValidation("Authorization", authorization!);

            try
            {
                var response = await client.SendAsync(request);
                var result = await response.Content.ReadFromJsonAsync<T>();
                return result;
            }
            catch (Exception ex)
            {
                requestInfo.Fail(ex);
            }
            return default;
        }

        /// <summary>
        /// 获取签名
        /// </summary>
        /// <param name="Method"> HTTP 请求方法，GET 或 POST</param>
        /// <param name="QueryString">查询字符串</param>
        /// <param name="Headers">请求头</param>
        /// <param name="RequestPayload">请求体</param>
        /// <param name="ak"> AccessKeyID </param>
        /// <param name="sk"> SecretAccessKey </param>
        /// <returns></returns>
        public static string Sign(string Method,
                string serviceName,
                Dictionary<string, string> QueryString,
                Dictionary<string, string> Headers,
                string RequestPayload,
                string ak, string sk, string Region)
        {
            string HTTPRequestMethod = Method;
            string CanonicalURI = "/";
            var sortedParams = QueryString.OrderBy(p => p.Key, StringComparer.Ordinal);
            string CanonicalQueryString = string.Join("&", sortedParams.Select(p =>
                $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}"));
            var sortedHeaders = Headers.OrderBy(h => h.Key, StringComparer.OrdinalIgnoreCase);
            string CanonicalHeaders = string.Join("\n", sortedHeaders.Select(h =>
                $"{h.Key.ToLower()}:{h.Value.Trim()}"));
            string SignedHeaders = string.Join(";", sortedHeaders.Select(h => h.Key.ToLower()));

            string CanonicalRequest =
                    HTTPRequestMethod + '\n' +
                    CanonicalURI + '\n' +
                    CanonicalQueryString + '\n' +
                    CanonicalHeaders + '\n' +
                    '\n' +
                    SignedHeaders + '\n' +
                    HexEncode(Hash(RequestPayload));

            string Algorithm = "HMAC-SHA256";
            string RequestDate = Headers["x-date"];
            string CredentialScope = $"{RequestDate.Substring(0, 8)}/{Region}/{serviceName}/request";

            string StringToSign =
                    Algorithm + '\n' +
                    RequestDate + '\n' +
                    CredentialScope + '\n' +
                    HexEncode(Hash(CanonicalRequest));

            string kSecret = sk;
            string kDate = HmacSecretKey(kSecret, RequestDate.Substring(0, 8));
            string kRegion = Hmac(kDate, Region);
            string kService = Hmac(kRegion, serviceName);
            string kSigning = Hmac(kService, "request");

            string Signature = Hmac(kSigning, StringToSign);

            string Credential = $"{ak}/{CredentialScope}";
            string Authorization = $"{Algorithm} Credential={Credential}, SignedHeaders={SignedHeaders}, Signature={Signature}";

            return Authorization;
        }

        // SHA256 哈希算法
        private static byte[] Hash(string input)
        {
            using (System.Security.Cryptography.SHA256 sha256 = System.Security.Cryptography.SHA256.Create())
            {
                return sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
            }
        }
        // 16 进制编码
        private static string HexEncode(byte[] data)
        {
            return BitConverter.ToString(data).Replace("-", "").ToLower();
        }


        private static string HmacSecretKey(string key, string message)
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            using System.Security.Cryptography.HMACSHA256 hmac = new System.Security.Cryptography.HMACSHA256(keyBytes);
            byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
            return HexEncode(hashBytes);
        }

        //Hmac_SHA256 哈希算法
        private static string Hmac(string key, string message)
        {
            // 将16进制字符串转换为字节数组
            byte[] keyBytes = new byte[key.Length / 2];
            for (int i = 0; i < keyBytes.Length; i++)
            {
                keyBytes[i] = Convert.ToByte(key.Substring(i * 2, 2), 16);
            }
            using System.Security.Cryptography.HMACSHA256 hmac = new System.Security.Cryptography.HMACSHA256(keyBytes);
            byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
            return HexEncode(hashBytes);
        }

        private static string QueryParamsToString(Dictionary<string, string> paramsDict)
        {
            return string.Join("&", paramsDict
                .OrderBy(kv => kv.Key)
                .Select(kv =>
                {
                    var val = kv.Value;
                    if (val == null) return null;

                    var escapedKey = UriEscape(kv.Key);
                    if (string.IsNullOrEmpty(escapedKey)) return null;

                    return $"{escapedKey}={UriEscape(val)}";
                })
                .Where(v => v != null));
        }

        private static (string signedHeaders, string canonicalHeaders) GetSignHeaders(
            Dictionary<string, string> originHeaders, List<string> needSignHeaders)
        {
            string TrimHeaderValue(object header)
            {
                return header?.ToString()?.Trim()?.Replace("  ", " ") ?? "";
            }

            var h = originHeaders.Keys.ToList();

            // 根据 needSignHeaders 过滤
            if (needSignHeaders.Any())
            {
                var needSignSet = new HashSet<string>(
                    needSignHeaders.Concat(new[] { "x-date", "host" })
                        .Select(k => k.ToLower()));
                h = h.Where(k => needSignSet.Contains(k.ToLower())).ToList();
            }

            // 根据 ignore headers 过滤
            h = h.Where(k => !HEADER_KEYS_TO_IGNORE.Contains(k.ToLower())).ToList();

            var signedHeaderKeys = string.Join(";",
                h.Select(k => k.ToLower()).OrderBy(k => k));

            var canonicalHeaders = string.Join("\n",
                h.OrderBy(k => k.ToLower())
                 .Select(k => $"{k.ToLower()}:{TrimHeaderValue(originHeaders[k])}"));

            return (signedHeaderKeys, canonicalHeaders);
        }

        private static string UriEscape(string str)
        {
            try
            {
                return HttpUtility.UrlEncode(str)?.Replace("*", "%2A")!;
            }
            catch
            {
                return "";
            }
        }

        private static string GetDateTimeNow()
        {
            return DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ");
        }
    }
}
