using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CrazyStudio.Core.Common.Tools
{
    public class AliyunTokenTool
    {
        public static async Task<string> GetAccessTokenAsync(string accessKeyId, string accessKeySecret)
        {
            var queryParamsMap = new Dictionary<string, string>();

            queryParamsMap.Add("AccessKeyId", accessKeyId);
            queryParamsMap.Add("Action", "CreateToken");
            queryParamsMap.Add("Version", "2019-02-28");
            queryParamsMap.Add("Timestamp", GetISO8601Time());
            queryParamsMap.Add("Format", "JSON");
            queryParamsMap.Add("RegionId", "cn-shanghai");
            queryParamsMap.Add("SignatureMethod", "HMAC-SHA1");
            queryParamsMap.Add("SignatureVersion", "1.0");
            queryParamsMap.Add("SignatureNonce", GetUniqueNonce());

            string queryString = CanonicalizedQuery(queryParamsMap);

            string method = "GET";
            string urlPath = "/";
            string stringToSign = CreateStringToSign(method, urlPath, queryString);

            string signature = Sign(stringToSign, accessKeySecret + "&");

            string queryStringWithSign = "Signature=" + signature + "&" + queryString;

            var url = "https://nls-meta.cn-shanghai.aliyuncs.com/?" + queryStringWithSign;

            var client = new HttpClient();
            var response = await client.GetAsync(url);
            var json = await response.Content.ReadAsStringAsync();
            response.Dispose();
            client.Dispose();

            return json;
        }

        private static string GetISO8601Time()
        {
            return DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
        }

        private static string GetUniqueNonce()
        {
            return Guid.NewGuid().ToString();
        }

        private static string PercentEncode(string value)
        {
            return Uri.EscapeDataString(value);
        }

        private static string CanonicalizedQuery(Dictionary<string, string> queryParamsMap)
        {
            var sortedKeys = queryParamsMap.Keys.Order();
            var canonicalizedQueryString = new StringBuilder();
            foreach (var key in sortedKeys)
            {
                canonicalizedQueryString
                    .Append('&')
                    .Append(PercentEncode(key))
                    .Append('=')
                    .Append(PercentEncode(queryParamsMap[key]));
            }
            return canonicalizedQueryString.ToString().Substring(1);
        }

        private static string CreateStringToSign(string method, string urlPath, string queryString)
        {
            var strBuilderSign = new StringBuilder();
            strBuilderSign.Append(method);
            strBuilderSign.Append('&');
            strBuilderSign.Append(PercentEncode(urlPath));
            strBuilderSign.Append('&');
            strBuilderSign.Append(PercentEncode(queryString));
            return strBuilderSign.ToString();
        }

        private static string Sign(string stringToSign, string accessKeySecret)
        {
            var key = Encoding.UTF8.GetBytes(accessKeySecret);
            var source = Encoding.UTF8.GetBytes(stringToSign);
            var signData = HMACSHA1.HashData(key, source);
            var signBase64 = Convert.ToBase64String(signData);
            var signUrlEncode = PercentEncode(signBase64);
            return signUrlEncode;
        }
    }
}
