using CrazyStudio.Core.Common.WeChat;
using CrazyStudio.Core.CryptHelper;
using CrazyStudio.Core.Pay.TenPay.Lib;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace CrazyStudio.Core.Pay.TenPay.Business
{
    public class JsApiPay
    {
        /// <summary>
        /// 保存页面对象，因为要在类的方法中使用Page的Request对象
        /// </summary>
        private HttpContext context { get; set; }

        /// <summary>
        /// openid用于调用统一下单接口
        /// </summary>
        public string openid { get; set; } = string.Empty;

        /// <summary>
        /// access_token用于获取收货地址js函数入口参数
        /// </summary>
        public string access_token { get; set; } = string.Empty;

        /// <summary>
        /// 商户数据包（string(128)）。腾讯官方给的定义，不知道具体有什么用。
        /// </summary>
        public string attach { get; set; } = string.Empty;

        /// <summary>
        /// 商品金额，用于统一下单
        /// </summary>
        public int total_fee { get; set; }

        /// <summary>
        /// 商户订单号，用于统一下单
        /// </summary>
        public string orderId { get; set; } = string.Empty;

        /// <summary>
        /// 商品描述，用于统一下单
        /// </summary>
        public string body { get; set; } = string.Empty;

        /// <summary>
        /// 商品标签，用于统一下单
        /// </summary>
        public string goods_tag { get; set; } = string.Empty;

        public string prepay_id { get; set; } = string.Empty;

        /// <summary>
        /// 统一下单接口返回结果
        /// </summary>
        public WxPayData? unifiedOrderResult { get; set; }

        public JsApiPay(HttpContext context)
        {
            this.context = context;
        }

        /**
        * 
        * 网页授权获取用户基本信息的全部过程
        * 详情请参看网页授权获取用户基本信息：http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
        * 第一步：利用url跳转获取code
        * 第二步：利用code去获取openid和access_token
        * 
        */
        //public void GetCodeAndRedirect(string redirect_uri, string loginType)
        //{
        //    //if (string.IsNullOrEmpty(redirect_uri))
        //    //{
        //    //    //获取code码，以获取openid和access_token
        //    //    string code = context.Request.Query["code"];
        //    //    Log.Debug(this.GetType().ToString(), "Get code : " + code);
        //    //    GetOpenidAndAccessTokenFromCode(code);
        //    //    return "";
        //    //}
        //    //else
        //    //{
        //    //构造网页授权获取code的URL
        //    //string host = context.Request.Url.Host;
        //    //string path = context.Request.Path;
        //    //string query = context.Request.Url.Query;
        //    //string redirect_uri = HttpUtility.UrlEncode("http://" + host + path + query);

        //    WxPayData data = new WxPayData();
        //    data.SetValue("appid", WxPayConfig.MP_APPID);

        //    //redirect_uri = redirect_uri.Replace("http://", "https://");

        //    //redirect_uri = HttpUtility.UrlEncode(redirect_uri);
        //    data.SetValue("redirect_uri", redirect_uri);

        //    //Log.Debug("redirect_uri", redirect_uri);

        //    data.SetValue("response_type", "code");
        //    data.SetValue("scope", loginType);
        //    data.SetValue("state", "STATE" + "#wechat_redirect");
        //    string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();

        //    //Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url);
        //    try
        //    {
        //        //触发微信返回code码         
        //        context.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常，不用处理这个异常
        //    }
        //    catch (System.Threading.ThreadAbortException ex)
        //    {
        //    }
        //    //}
        //}

        /// <summary>
        /// 申请退款
        /// </summary>
        /// <param name="inputObj">提交给申请退款API的参数</param>
        /// <param name="CertPath">证书路径</param>
        /// <param name="CertPassword">证书密码</param>
        /// <param name="timeOut">超时时间</param>
        /// <returns></returns>
        public PaymentData Refund(PaymentData inputObj, string notify_url, int timeOut = 10)
        {
            string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            //检测必填参数
            if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
            {
                throw new Exception("退款申请接口中，out_trade_no、transaction_id至少填一个！");
            }
            else if (!inputObj.IsSet("out_refund_no"))
            {
                throw new Exception("退款申请接口中，缺少必填参数out_refund_no！");
            }
            else if (!inputObj.IsSet("total_fee"))
            {
                throw new Exception("退款申请接口中，缺少必填参数total_fee！");
            }
            else if (!inputObj.IsSet("refund_fee"))
            {
                throw new Exception("退款申请接口中，缺少必填参数refund_fee！");
            }
            else if (!inputObj.IsSet("op_user_id"))
            {
                throw new Exception("退款申请接口中，缺少必填参数op_user_id！");
            }

            inputObj.SetValue("notify_url", notify_url);//公众账号ID
            inputObj.SetValue("appid", WxPayConfig.MP_APPID);//公众账号ID
            inputObj.SetValue("mch_id", WxPayConfig.MP_MCHID);//商户号
            inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
            inputObj.SetValue("sign", inputObj.MakeSign(WxPayConfig.MCHKEY));//签名
            string xml = inputObj.ToXml();
            string response = HttpService.Post(xml, url, true, timeOut, WxPayConfig.SSLCERT_PATH, WxPayConfig.SSLCERT_PASSWORD);
            //将xml格式的结果转换为对象以返回
            PaymentData result = new PaymentData();
            result.FromXml(response);
            return result;
        }

        /**
	    * 
	    * 通过code换取网页授权access_token和openid的返回数据，正确时返回的JSON数据包如下：
	    * {
	    *  "access_token":"ACCESS_TOKEN",
	    *  "expires_in":7200,
	    *  "refresh_token":"REFRESH_TOKEN",
	    *  "openid":"OPENID",
	    *  "scope":"SCOPE",
	    *  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
	    * }
	    * 其中access_token可用于获取共享收货地址
	    * openid是微信支付jsapi支付接口统一下单时必须的参数
        * 更详细的说明请参考网页授权获取用户基本信息：http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
        * @失败时抛异常WxPayException
	    */
        public string GetOpenidAndAccessTokenFromCode(string code)
        {
            try
            {
                //构造获取openid及access_token的url
                WxPayData data = new WxPayData();
                data.SetValue("appid", WxPayConfig.MP_APPID);
                data.SetValue("secret", WxPayConfig.MP_APPSECRET);
                Log.Debug("SF_APPSECRET", WxPayConfig.MP_APPSECRET);
                data.SetValue("code", code);
                data.SetValue("grant_type", "authorization_code");

                string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl();

                //请求url以获取数据
                string result = HttpService.Get(url);

                //Log.Debug(this.GetType().ToString(), "GetOpenidAndAccessTokenFromCode response : " + result);

                //保存access_token，用于收货地址获取
                //JsonData jd = JsonMapper.ToObject(result);
                var jd = JsonConvert.DeserializeObject(result) as JObject;
                access_token = (string)jd!["access_token"]!;

                //获取用户openid
                openid = (string)jd!["openid"]!;

                return openid;

                //Log.Debug(this.GetType().ToString(), "Get openid : " + openid);
                //Log.Debug(this.GetType().ToString(), "Get access_token : " + access_token);
            }
            catch (Exception ex)
            {
                Log.Error(this.GetType().ToString(), ex.ToString());
                throw new WxPayException(ex.ToString());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="out_trade_no">调用统一下单，获得下单结果</param>
        /// <returns>统一下单结果。失败时抛异常WxPayException</returns>
        public WxPayData GetUnifiedOrderResult(ref string out_trade_no)
        {
            //统一下单
            WxPayData data = new WxPayData();
            data.SetValue("body", body);
            data.SetValue("attach", attach);
            //订单号
            data.SetValue("out_trade_no", out_trade_no);
            data.SetValue("total_fee", total_fee);
            data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
            data.SetValue("time_expire", DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss"));
            data.SetValue("goods_tag", goods_tag);
            data.SetValue("trade_type", "JSAPI");
            data.SetValue("openid", openid);

            WxPayData result = WxPayApi.UnifiedOrder(data, WxPayConfig.IP, 60);
            if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
            {
                Log.Error(this.GetType().ToString(), "UnifiedOrder response error!" + result.ToJson());
                throw new WxPayException("UnifiedOrder response error!openid: " + openid + " " + result.ToJson());
            }

            unifiedOrderResult = result;
            return result;
        }

        /**
        *  
        * 从统一下单成功返回的数据中获取微信浏览器调起jsapi支付所需的参数，
        * 微信浏览器调起JSAPI时的输入参数格式如下：
        * {
        *   "appId" : "wx2421b1c4370ec43b",     //公众号名称，由商户传入     
        *   "timeStamp":" 1395712654",         //时间戳，自1970年以来的秒数     
        *   "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串     
        *   "package" : "prepay_id=u802345jgfjsdfgsdg888",     
        *   "signType" : "MD5",         //微信签名方式:    
        *   "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
        * }
        * @return string 微信浏览器调起JSAPI时的输入参数，json格式可以直接做参数用
        * 更详细的说明请参考网页端调起支付API：http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7
        * 
        */
        public string GetJsApiParameters()
        {
            Log.Debug(this.GetType().ToString(), "JsApiPay::GetJsApiParam is processing...");

            WxPayData jsApiParam = new WxPayData();
            jsApiParam.SetValue("appId", unifiedOrderResult!.GetValue("appid"));
            jsApiParam.SetValue("timeStamp", WxPayApi.GenerateTimeStamp());
            jsApiParam.SetValue("nonceStr", WxPayApi.GenerateNonceStr());
            jsApiParam.SetValue("package", "prepay_id=" + unifiedOrderResult.GetValue("prepay_id"));
            jsApiParam.SetValue("signType", "MD5");
            jsApiParam.SetValue("paySign", jsApiParam.MakeSign());

            string parameters = jsApiParam.ToJson();

            Log.Debug(this.GetType().ToString(), "Get jsApiParam : " + parameters);
            return parameters;
        }


        /**
	    * 
	    * 获取收货地址js函数入口参数,详情请参考收货地址共享接口：http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_9
	    * @return string 共享收货地址js函数需要的参数，json格式可以直接做参数使用
	    */
        public string GetEditAddressParameters()
        {
            string parameter;
            try
            {
                string host = context.Request.Host.Host;//context.Request.Url.Host;
                string path = context.Request.Path;
                string queryString = context.Request.QueryString.Value;//context.Request.Url.Query; 
                //这个地方要注意，参与签名的是网页授权获取用户信息时微信后台回传的完整url
                string url = "http://" + host + path + queryString;

                //构造需要用SHA1算法加密的数据
                WxPayData signData = new WxPayData();
                signData.SetValue("appid", WxPayConfig.MP_APPID);
                signData.SetValue("url", url);
                signData.SetValue("timestamp", WxPayApi.GenerateTimeStamp());
                signData.SetValue("noncestr", WxPayApi.GenerateNonceStr());
                signData.SetValue("accesstoken", access_token);
                string param = signData.ToUrl();

                Log.Debug(this.GetType().ToString(), "SHA1 encrypt param : " + param);
                //SHA1加密
                string addrSign = SHA1Crypt.SHA1HashString(param);//FormsAuthentication.HashPasswordForStoringInConfigFile(param, "SHA1");
                Log.Debug(this.GetType().ToString(), "SHA1 encrypt result : " + addrSign);

                //获取收货地址js函数入口参数
                WxPayData afterData = new WxPayData();
                afterData.SetValue("appId", WxPayConfig.MP_APPID);
                afterData.SetValue("scope", "jsapi_address");
                afterData.SetValue("signType", "sha1");
                afterData.SetValue("addrSign", addrSign);
                afterData.SetValue("timeStamp", signData.GetValue("timestamp"));
                afterData.SetValue("nonceStr", signData.GetValue("noncestr"));

                //转为json格式
                parameter = afterData.ToJson();
                Log.Debug(this.GetType().ToString(), "Get EditAddressParam : " + parameter);
            }
            catch (Exception ex)
            {
                Log.Error(this.GetType().ToString(), ex.ToString());
                throw new WxPayException(ex.ToString());
            }

            return parameter;
        }
    }
}