using CrazyStudio.Core.Common.CryptHelper;
using CrazyStudio.Core.CryptHelper;
using CrazyStudio.Core.Pay.TenPay.Lib;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System.Collections;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;

namespace CrazyStudio.Core.Common.WeChat
{
    public class WeChatCommon
    {
        //private static string appOpenId = "";// ConfigExtensions.Configuration["WeChat:Open:AppID"];//微信开放平台appId
        //private static string appId = "";// ConfigExtensions.Configuration["WeChat:MP:AppID"];//微信公众平台appId
        //private static string webAppId = "";// ConfigExtensions.Configuration["WeChat:Open:Web:AppID"];//微信公众平台网站appId
        //private static string appSecret = "";// ConfigExtensions.Configuration["WeChat:MP:AppSecret"];//微信公众平台appSecret
        //public static readonly string serverAppId = ConfigurationManager.AppSettings["WeChat.ServerAppID"];//微信平台公众服务号appId
        //private static string mchid = "";// ConfigExtensions.Configuration["WeChat.MchID"];//注：商务ID
        //private static string appMchkey = "";// ConfigExtensions.Configuration["WeChat:MchKEY"];//注：MchKey为商户平台设置的密钥key 
        //private static string notify_url = "";// ConfigExtensions.Configuration["WeChat:NOTIFY_URL"];//支付完成后微信通知回调页面

        private const string WxCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&state={2}&scope={3}#wechat_redirect";

        /// <summary>
        /// 小程序登录凭证校验
        /// </summary>
        private const string WxMiniLoginCodeUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";

        public static WeChatCommon Instance
        {
            get
            {
                return SingletonProvider<WeChatCommon>.Instance;
            }
        }

        private static string ACCESS_TOKEN = string.Empty;

        private static DateTime prevGetTokenTime = DateTime.MinValue;

        private static DateTime prevGetTicketTime = DateTime.MinValue;

        private static string JSAPI_TICKET = string.Empty;

        //private static readonly object token_SyncObject = new object();

        //private static readonly object ticket_SyncObject = new object();

        private static string[] strs = new string[]
                                 {
                                  "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
                                  "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
                                 };


        public async Task<string> GetUrl(string Url, Encoding enc = null)
        {
            try
            {
                if (enc == null)
                    enc = Encoding.UTF8;

                var wReq = new HttpClient();

                wReq.Timeout = TimeSpan.FromSeconds(60);//超时时间60秒

                var wResp = await wReq.GetAsync(Url);

                System.IO.Stream respStream = wResp.Content.ReadAsStream();

                using (System.IO.StreamReader reader = new System.IO.StreamReader(respStream, enc))
                {
                    return reader.ReadToEnd();
                }
            }
            catch (Exception)
            {
                //ActionLogManager actionLogManager = new ActionLogManager();
                //var actionLog = new action_log
                //{
                //    ID = 0,
                //    LogTime = DateTime.Now,
                //    Memo = "获取Code错误详细信息：" + ex.Message + " " + ex.StackTrace,
                //    ActionID = -1,//系统异常日志
                //    ObjectID = 0
                //};
                //actionLogManager.AddLog(actionLog);


                //errorMsg = ex.Message;
            }
            return "";
        }

        public async Task<string> RefreshAccessToken(string code)
        {
            var result = await HttpRequestHelper.Get(" https://api.weixin.qq.com/sns/oauth2/refresh_token", $"appid={WxPayConfig.WeChatOptions.AppID}&grant_type=refresh_token&refresh_token=REFRESH_TOKEN");
            return result;
        }

        private async Task<string> GetAccessToken()
        {
            if (prevGetTokenTime == DateTime.MinValue || DateTime.Now > prevGetTokenTime.AddHours(1))
            {
                if (prevGetTokenTime == DateTime.MinValue || DateTime.Now > prevGetTokenTime.AddHours(1))
                {
                    //SystemLogManager logManager = new SystemLogManager();
                    //logManager.AddSystemLog(new DataAccess.system_log
                    //{
                    //    LogType = 1,
                    //    LogTime = DateTime.Now,
                    //    Memo = string.Format("prevGetTokenTime:{0}, ACCESS_TOKEN:{1}", prevGetTokenTime.ToString(), ACCESS_TOKEN)
                    //});

                    //string appId = ConfigExtensions.Configuration["WeChat:MP:AppID"];//ConfigurationManager.AppSettings["WeChat.MP.AppID"];
                    //string appSecert = ConfigExtensions.Configuration["WeChat:MP:APPSECRET"];//ConfigurationManager.AppSettings["WeChat.MP.APPSECRET"];
                    //string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecert;
                    string tokenJson = await HttpRequestHelper.Get("https://api.weixin.qq.com/cgi-bin/token", $"grant_type=client_credential&appid={WxPayConfig.WeChatOptions.AppID}&secret={WxPayConfig.WeChatOptions.AppSecret}");
                    if (!string.IsNullOrEmpty(tokenJson))
                    {
                        WxAccessTokenModel token = JsonConvert.DeserializeObject<WxAccessTokenModel>(tokenJson);
                        ACCESS_TOKEN = token!.access_token;
                        prevGetTokenTime = DateTime.Now;
                    }
                }
            }
            return ACCESS_TOKEN;
        }

        private async Task<string> GetAccessToken2()
        {
            //string appId = ConfigExtensions.Configuration["WeChat:MP:AppID"];//ConfigurationManager.AppSettings["WeChat.MP.AppID"];
            //string appSecert = ConfigExtensions.Configuration["WeChat:MP:APPSECRET"];//ConfigurationManager.AppSettings["WeChat.MP.APPSECRET"];
            string tokenJson = await HttpRequestHelper.Get("https://api.weixin.qq.com/cgi-bin/token", $"grant_type=client_credential&appid={WxPayConfig.WeChatOptions.AppID}&secret={WxPayConfig.WeChatOptions.AppSecret}");
            WxAccessTokenModel token = JsonConvert.DeserializeObject<WxAccessTokenModel>(tokenJson);
            var res = token != null ? token!.access_token : null;
            return res!;
        }


        public void GetCode(HttpContext http, string redirectUrl, string state, string snsapi_type)
        {
            string appId = WxPayConfig.WeChatOptions.AppID;

            //var wxRedirectUrl = ConfigExtensions.Configuration["WeChat:RedirectHost"] + "/wechat/wxRedirect.html";
            string returnUrl = string.Format(WxCodeUrl, appId, HttpUtility.UrlEncode(redirectUrl), state, snsapi_type);
            http.Response.Redirect(returnUrl);
        }

        public async Task<string> GetOpenId(string code)
        {
            string result = await HttpRequestHelper.Get("https://api.weixin.qq.com/sns/oauth2/access_token", $"appid={WxPayConfig.WeChatOptions.AppID}&secret={WxPayConfig.WeChatOptions.AppSecret}&code={code}&grant_type=authorization_code");

            return result;
        }

        public async Task<string> GetUnionId(string accessToken, string openId)
        {
            string result = await HttpRequestHelper.Get("https://api.weixin.qq.com/sns/userinfo", $"access_token={accessToken}&openid={openId}&lang=zh_CN");
            return result;

        }

        public async Task<string> GetMiniCodeInfo(string code)
        {
            string appId = WxPayConfig.WeChatOptions.AppID;
            string appSecret = WxPayConfig.WeChatOptions.AppSecret;

            //Console.WriteLine("appId:" + appId);
            //Console.WriteLine("appSecret:" + appSecret);

            //var wxRedirectUrl = ConfigExtensions.Configuration["WeChat:RedirectHost"] + "/wechat/wxRedirect.html";
            string url = string.Format(WxMiniLoginCodeUrl, appId, appSecret, code);

            var res = await GetUrl(url);

            return res;
        }

        public async Task<WxAccessTokenModel> GetUserInfo(string code)
        {
            try
            {
                string url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + WxPayConfig.WeChatOptions.AppID + "&secret=" + WxPayConfig.WeChatOptions.AppSecret + "&code=" + code + "&grant_type=authorization_code";
                string tokenJson = await GetUrl(url);
                Log.Error("tokenJson", tokenJson);
                if (!string.IsNullOrEmpty(tokenJson))
                {
                    WxAccessTokenModel? token = JsonConvert.DeserializeObject<WxAccessTokenModel>(tokenJson);
                    return token!;
                }
                else
                {
                    //ActionLogManager actionLogManager = new ActionLogManager();
                    //var actionLog = new action_log
                    //{
                    //    ID = 0,
                    //    LogTime = DateTime.Now,
                    //    Memo = "获取Code错误：url:" + url,// + ex.Message + " " + ex.StackTrace,
                    //    ActionID = -1,//系统异常日志
                    //    ObjectID = 0
                    //};
                    //actionLogManager.AddLog(actionLog);
                }
            }
            catch (Exception)
            {
                //ActionLogManager actionLogManager = new ActionLogManager();
                //var actionLog = new action_log
                //{
                //    ID = 0,
                //    LogTime = DateTime.Now,
                //    Memo = "获取Code错误：" + ex.Message + " " + ex.StackTrace,
                //    ActionID = -1,//系统异常日志
                //    ObjectID = 0
                //};
                //actionLogManager.AddLog(actionLog);
            }
            return null;
        }

        private async Task<string> GetJsApiTicket()
        {
            if (JSAPI_TICKET == null || prevGetTicketTime == DateTime.MinValue || DateTime.Now > prevGetTicketTime.AddHours(1))
            {
                string access_Token = await GetAccessToken();

                string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_Token + "&type=jsapi";
                string jsApi_Ticket = await GetUrl(url);

                if (!string.IsNullOrEmpty(jsApi_Ticket))
                {
                    var tickEntity = JsonConvert.DeserializeObject<WeChatTicket>(jsApi_Ticket);
                    JSAPI_TICKET = tickEntity!.ticket;
                    prevGetTicketTime = DateTime.Now;
                }
            }
            return JSAPI_TICKET!;
        }

        public string Task<MD5_Hash>(string str_md5_in)
        {
            MD5 md5 = MD5.Create();
            byte[] bytes_md5_in = Encoding.Default.GetBytes(str_md5_in);
            byte[] bytes_md5_out = md5.ComputeHash(bytes_md5_in);
            string str_md5_out = BitConverter.ToString(bytes_md5_out);
            //str_md5_out = str_md5_out.Replace("-", "");
            return str_md5_out;
        }

        //SHA1
        public string SHA1_Hash(string str_sha1_in)
        {
            SHA1 sha1 = SHA1.Create();
            byte[] bytes_sha1_in = Encoding.Default.GetBytes(str_sha1_in);
            byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in);
            string str_sha1_out = BitConverter.ToString(bytes_sha1_out);
            str_sha1_out = str_sha1_out.Replace("-", "");
            return str_sha1_out;
        }

        private string CreateSignature(string jsTicket, string nonceStr, string timestamp, string url)
        {
            //WeChatTicket weichatTicket = JsonConvert.DeserializeObject<WeChatTicket>(jsTicket);

            //string domain = ConfigurationManager.AppSettings["DOMAIN"];

            string[] ArrayList = { "jsapi_ticket=" + jsTicket, "noncestr=" + nonceStr, "timestamp=" + timestamp, "url=" + url };
            //Array.Sort(ArrayList);
            string content = string.Join("&", ArrayList);
            string signature = SHA1_Hash(content);
            signature = signature.ToLower();

            return signature;
        }

        /// <summary>
        /// 创建随机字符串
        ///本代码来自开源微信SDK项目：https://github.com/night-king/weixinSDK
        /// </summary>
        /// <returns></returns>
        public static string CreatenNonceStr()
        {
            Random r = new Random();
            var sb = new StringBuilder();
            var length = strs.Length;
            for (int i = 0; i < 15; i++)
            {
                sb.Append(strs[r.Next(length - 1)]);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 创建时间戳
        ///本代码来自开源微信SDK项目：https://github.com/night-king/weixinSDK
        /// </summary>
        /// <returns></returns>
        public static long CreatenTimestamp()
        {
            return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
        }

        public async Task<WeChatJsConfig> GetConfig(string url)
        {
            WeChatJsConfig config = new WeChatJsConfig();
            if (url.IndexOf('#') > -1)
                url = url.Substring(0, url.IndexOf('#'));

            config.appId = WxPayConfig.WeChatOptions.AppID;//ConfigExtensions.Configuration["WeChat:MP:AppID"];
            config.timestamp = CreatenTimestamp().ToString();
            config.nonceStr = CreatenNonceStr();

            string jsTicket = await GetJsApiTicket();
            config.signature = CreateSignature(jsTicket, config.nonceStr, config.timestamp, url);

            return config;
        }

        ///// <summary>
        ///// 取得永久二维码URL
        ///// </summary>
        //public async Task<string> GetForeverQRCode()
        //{
        //    //string access_Token = getAccessToken();

        //    ////获取数据的地址（微信提供）
        //    //string url = string.Format(new WxWebConfig().WxAccessToken, access_Token);


        //    ////发送给微信服务器的数据
        //    //string paramStr = "{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": 1000}}}";//"{'expire_seconds': '604800', 'action_name': 'QR_STR_SCENE', 'action_info': {'scene': {'scene_str': '" + refererId + "'}}}";
        //    //                                                                                                                                  //string jsonStr = JsonConvert.SerializeObject(paramStr);

        //    ////将得到的字符串转化成json对象
        //    //string response = HttpUtil.WebRequestPostOrGet(url, paramStr);

        //    //WechatTicket ticketInfo = JsonConvert.DeserializeObject<WechatTicket>(response);

        //    //string result = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticketInfo.ticket;

        //    //return result;

        //    return "";
        //}

        ///// <summary>
        ///// 取得临时二维码
        ///// </summary>
        //public static string GetTemporaryQR()
        //{
        //    var refererId = 0;

        //    string access_Token = getAccessToken();

        //    //获取数据的地址（微信提供）
        //    string url = string.Format(new WxWebConfig().WxAccessToken, access_Token);


        //    //发送给微信服务器的数据
        //    //string paramStr = "{\"expire_seconds\": 604800, \"action_name\": \"QR_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"" + refererId + "\"}}}";
        //    string paramStr = "{\"expire_seconds\": 604800, \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": " + refererId + "}}}";

        //    //将得到的字符串转化成json对象
        //    string response = HttpUtil.WebRequestPostOrGet(url, paramStr);

        //    try
        //    {
        //        var wxQrCode = JsonConvert.DeserializeObject<WxQRCodeModel>(response);
        //        string ticket = wxQrCode.ticket;
        //        return ticket;
        //    }
        //    catch
        //    {
        //        return "error";
        //    }
        //}

        public class Wx_Pay_Model
        {
            //public int retcode { get; set; }
            //public string retmsg { get; set; } = string.Empty;
            public string appid { get; set; } = string.Empty;
            public string nonceStr { get; set; } = string.Empty;
            public string package { get; set; } = string.Empty;
            public string partnerid { get; set; } = string.Empty;
            public string prepayid { get; set; } = string.Empty;
            public string timestamp { get; set; } = string.Empty;
            public string sign { get; set; } = string.Empty;
            public string signType { get; set; } = "MD5";
        }

        /// <summary>
        /// 输出XML
        /// </summary>
        /// <returns></returns>
        public static string parseXML(Hashtable _parameters)
        {
            var sb = new StringBuilder();
            sb.Append("<xml>");
            var akeys = new ArrayList(_parameters.Keys);
            foreach (string k in akeys)
            {
                var v = (string?)_parameters[k];
                if (v != null)
                {
                    if (Regex.IsMatch(v!, @"^[0-9.]$"))
                    {
                        sb.Append("<" + k + ">" + v + "</" + k + ">");
                    }
                    else
                    {
                        sb.Append("<" + k + "><![CDATA[" + v + "]]></" + k + ">");
                    }
                }
            }
            sb.Append("</xml>");
            return sb.ToString();
        }

        /// <summary>
        /// 创建package签名
        /// </summary>
        /// <param name="key">密钥键</param>
        /// <param name="value">财付通商户密钥（自定义32位密钥）</param>
        /// <returns></returns>
        public static string CreateSign(Hashtable parameters, string sign_type = "MD5")
        {
            var sb = new StringBuilder();
            var akeys = new ArrayList(parameters.Keys);
            akeys.Sort();//排序，这是微信要求的
            foreach (string k in akeys)
            {
                var v = (string)parameters[k]!;
                sb.Append(k + "=" + v + "&");
            }
            sb.Append("key=" + WxPayConfig.WeChatOptions.MchKey);

            string sign = "";
            if (sign_type == "MD5")
            {
                sign = MD5Crypt.GetMD5(sb.ToString());
            }
            else if (sign_type == "HMACSHA256")
            {
                sign = SHA1Crypt.GetHMACSHA256(sb.ToString(), WxPayConfig.WeChatOptions.MchKey);
            }
            return sign;
        }

        public static Wx_Pay_Model GetPayInfo(WxPayData payData)
        {
            //为发送请求给微信服务器准备数据
            var nstr = CreatenNonceStr();
            //为响应客户端的请求准备数据 
            var timeStamp = CreatenTimestamp();
            string prepayId = payData.GetValue("prepay_id") + "";
            string package = "prepay_id=" + prepayId;
            Hashtable paySignReqHandler = new Hashtable();
            paySignReqHandler.Add("appId", WxPayConfig.WeChatOptions.AppID);
            paySignReqHandler.Add("timeStamp", timeStamp.ToString());
            paySignReqHandler.Add("nonceStr", nstr);
            paySignReqHandler.Add("package", package);
            string signType = "MD5";
            paySignReqHandler.Add("signType", signType);
            var paySign = CreateSign(paySignReqHandler, signType);  //签名
            var result = new Wx_Pay_Model
            {
                appid = WxPayConfig.WeChatOptions.AppID,
                partnerid = WxPayConfig.WeChatOptions.MchID,
                prepayid = prepayId,
                package = package,
                nonceStr = nstr,
                timestamp = timeStamp.ToString(),
                sign = paySign,
                signType = signType
            };
            return result;
        }

        public string GetAppID()
        {
            return WxPayConfig.WeChatOptions.AppID;
        }

        //public string GetOpenAppID()
        //{
        //    return appOpenId;
        //}

        //public string GetWebAppID()
        //{
        //    return webAppId;
        //}
        public string GetAppSecret()
        {
            return WxPayConfig.WeChatOptions.AppSecret;
        }

    }
}
