using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Edu.Common.WeChatPayAPIv3.Model.GenerateOrder;
using Edu.Common.WeChatPayAPIv3.Model.QueryOrder;
using Edu.Common.WeChatPayAPIv3.Model.QueryRefunds;
using Edu.Common.WeChatPayAPIv3.Model.Refunds;

namespace Edu.Common.WeChatPayAPIv3
{

    public class WxPayHelper
    {
        /// <summary>
        /// 直连商户申请的公众号或移动应用appid。
        /// </summary>
        private string _appid { set; get; }

        /// <summary>
        /// 直连商户的商户号,由微信支付生成并下发。
        /// </summary>
        private string _mchid { set; get; }

        /// <summary>
        /// 证书序列号,查看证书序列号:https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao
        /// </summary>
        private string _serialNo;

        /// <summary>
        /// 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----     亦不包括结尾的-----END PRIVATE KEY-----
        /// </summary>
        private string _privateKey;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="appid">直连商户申请的公众号或移动应用appid</param>
        /// <param name="mchid">直连商户的商户号,由微信支付生成并下发</param>
        /// <param name="serialNo">证书序列号,查看证书序列号:https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao</param>
        /// <param name="privateKey">私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----     亦不包括结尾的-----END PRIVATE KEY-----</param>
        public WxPayHelper(string appid, string mchid, string serialNo, string privateKey)
        {
            _appid = appid;
            _mchid = mchid;
            _serialNo = serialNo;
            _privateKey = privateKey;
        }

        /// <summary>
        /// 统一下单接口,只对接了必填的字段
        /// </summary>
        /// <param name="description">商品描述</param>
        /// <param name="price">订单总金额,单位为分</param>
        /// <param name="out_trade_no">商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一</param>
        /// <param name="notify_url">通知URL必须为直接可访问的URL,不允许携带查询串。格式:URL</param>
        /// <param name="attach">附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用</param>
        /// <param name="currency">货币类型,CNY:人民币,境内商户号仅支持人民币</param>
        /// <returns></returns>
        public async Task<WxPayRespModel> UnionGenerateOrder(string description, int price, string out_trade_no, string notify_url, string attach = "", string currency = "CNY")
        {
            var url = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";
            var req = new GenerateOrderModelForWxPay
            {
                appid = this._appid,
                mchid = this._mchid,
                description = description,
                amount = new WxPayAmountModel
                {
                    total = price,
                    currency = currency
                },
                out_trade_no = out_trade_no,
                attach = attach,
                notify_url = notify_url
            };

            var client = new HttpClient(new WxPayRequestHandler(_mchid, _serialNo, _privateKey));
            //  var bodyJson = new StringContent(req.ToJson(), Encoding.UTF8, "application/json");
            var bodyJson = new StringContent(Common.Plugin.JsonHelper.Serialize(req), Encoding.UTF8, "application/json");
           
            var resp = await client.PostAsync(url, bodyJson);
            // 注意!!! 这个resp只是http的结果,需要把接口具体返回的值读取出来,如果接口报错的话,这地方可以看到具体的错误信息,我就是在这里入坑的。
            var respStr = await resp.Content.ReadAsStringAsync();

            // 如果下单成功,就解析返回的结果,把prepay_id解析出来
            // var viewModel = respStr.ToObject<WxPayRespModel>();
            Plugin.LogHelper.WriteInfo(respStr);
            var viewModel = Common.Plugin.JsonHelper.DeserializeObject<WxPayRespModel>(respStr);
            return viewModel;
        }

        /// <summary>
        /// 查询订单
        /// </summary>
        /// <param name="orderNumber">商户自己的订单号,不是微信生成的订单号</param>
        public async Task<WxPayStatusRespModel> QueryOrder(string orderNumber)
        {
            var url = $"https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{orderNumber}?mchid={ this._mchid}";
            var client = new HttpClient(new WxPayRequestHandler(_mchid, _serialNo, _privateKey));
            var resp = await client.GetAsync(url);
            var respStr = await resp.Content.ReadAsStringAsync();
            Plugin.LogHelper.WriteInfo("查询订单的支付结果信息:"+respStr);
            var payModel = Common.Plugin.JsonHelper.DeserializeObject<WxPayStatusRespModel>(respStr);// respStr.ToObject<WxPayStatusRespModel>();
            return payModel;
        }

        ///// <summary>
        ///// 关闭订单
        ///// </summary>
        ///// <param name="orderNumber">商户自己的订单号,不是微信生成的订单号</param>
        //public async Task<ClostOrderRespModel> ClostOrder(string orderNumber)
        //{
        //    var url = $"https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{orderNumber}/close";
        //    var client = new HttpClient(new WxPayRequestHandler(_mchid, _serialNo, _privateKey));
        //    var bodyJson = new StringContent(new { mchid = this._mchid }.ToJson(), Encoding.UTF8, "application/json");
        //    var resp = await client.PostAsync(url, bodyJson);
        //    var respStr = await resp.Content.ReadAsStringAsync();
        //    var closeModel = new ClostOrderRespModel();
        //    if (!string.IsNullOrEmpty(respStr))
        //        closeModel = respStr.ToObject<ClostOrderRespModel>();
        //    closeModel.StatusCode = resp.StatusCode.ToString();
        //    return closeModel;
        //}


        /// <summary>
        /// 微信支付申请退款接口
        /// </summary>
        /// <param name="out_trade_no">商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一;原支付交易对应的商户订单号。</param>
        /// <param name="out_refund_no">商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。</param>
        /// <param name="reason">若商户传入,会在下发给用户的退款消息中体现退款原因。</param>
        /// <param name="refund">退款金额,币种的最小单位,只能为整数,不能超过原订单支付金额。</param>
        /// <param name="total">原支付交易的订单总金额,币种的最小单位,只能为整数。</param>
        /// <param name="notify_url">异步接收微信支付退款结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 如果参数中传了notify_url,则商户平台上配置的回调地址将不会生效,优先回调当前传的这个地址。示例值:https://weixin.qq.com ,必须是https的网址</param>
        /// <param name="currency">符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。</param>
        /// <returns></returns>
        public async Task<RefundsRespModel> Refunds(string out_trade_no, string out_refund_no, string reason, int refund, int total, string notify_url = "", string currency = "CNY")
        {
            var req = new RefundsRequestModel
            {
                out_refund_no = out_refund_no,
                out_trade_no = out_trade_no,
                reason = reason,
                notify_url = notify_url,
                amount = new RefundsAmountModel
                {
                    refund = refund,
                    total = total,
                    currency = currency
                }
            };

            var url = $"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
            var client = new HttpClient(new WxPayRequestHandler(_mchid, _serialNo, _privateKey));
            var bodyJson = new StringContent(Common.Plugin.JsonHelper.Serialize(req), Encoding.UTF8, "application/json");

            var resp = await client.PostAsync(url, bodyJson);
            var respStr = await resp.Content.ReadAsStringAsync();

            var payModel = Common.Plugin.JsonHelper.DeserializeObject<RefundsRespModel>(respStr);// respStr.ToObject<RefundsRespModel>();
            return payModel;
        }

        /// <summary>
        /// 查询退款结果
        /// </summary>
        /// <param name="out_refund_no">商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。</param>
        public async Task<QueryRefundsOrderRespModel> QueryRefundsOrder(string out_refund_no)
        {
            var url = $"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{out_refund_no}";
            var client = new HttpClient(new WxPayRequestHandler(_mchid, _serialNo, _privateKey));
            var resp = await client.GetAsync(url);
            var respStr = await resp.Content.ReadAsStringAsync();
            Plugin.LogHelper.WriteInfo("查询订单的退款结果信息:" + respStr);
            var payModel = Common.Plugin.JsonHelper.DeserializeObject<QueryRefundsOrderRespModel>(respStr); //respStr.ToObject<QueryRefundsOrderRespModel>();
            return payModel;
        }
    }
}