using BaseModel.Models;
using System;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace Wechat.PayAPI
{
    public class Refund
    {
        private const int MAX_REFUND_RETRY_TIMES = 5;

        /***
        * 申请退款完整业务流程逻辑
        * @param transaction_id 微信订单号（优先使用）
        * @param out_trade_no 商户订单号
        * @param total_fee 订单总金额
        * @param refund_fee 退款金额
        * @return 退款结果
        */
        public static async Task<WxPayData> Run(string transaction_id, ElectronicOrderModel order)
        {
            // string out_trade_no, string total_fee, string refund_fee
            //set the default trade_status to PAYERROR
            order.TradeStatus = TradeStatus.PAYERROR;

            string out_refund_no = WxPayApi.GenerateOutTradeNo((WxPayConfig)order.Config);
            Log.Info("Refund", "Refund is processing, out_refund_no = " + out_refund_no);

            int retry_count = 0;
            bool use_unsettled_fund = true;
            while (true)
            {
                WxPayData result = await RequestRefund(transaction_id, 
                                                 order.BillNumber, 
                                                 order.TotalAmount.ToString(), 
                                                 order.NetAmount.ToString(), 
                                                 out_refund_no,
                                                 use_unsettled_fund,
                                                 (WxPayConfig)order.Config,
                                                 (X509Certificate2)order.Certification);

                //如果提交退款接口调用失败，则抛异常
                if (!result.IsSet("return_code") || result.GetValue("return_code").ToString() == "FAIL")
                {
                    string returnMsg = result.IsSet("return_msg") ? result.GetValue("return_msg").ToString() : "";
                    Log.Error("MicroPay", "Micropay API interface call failure, result : " + result.ToXml());
                    throw new WxPayException("Micropay API interface call failure, return_msg : " + returnMsg);
                }

                //签名验证
                result.CheckSign((WxPayConfig)order.Config);
                Log.Debug("MicroPay", "Micropay response check sign success");

                //退款成功
                if (result.GetValue("return_code").ToString() == "SUCCESS" &&
                    result.GetValue("result_code").ToString() == "SUCCESS")
                {
                    Log.Debug("MicroPay", "Micropay refund success, result : " + result.ToXml());
                    order.TradeStatus = TradeStatus.SUCCESS;
                    return result;
                }

                /******************************************************************
                 * 剩下的都是接口调用成功，业务失败的情况
                 * ****************************************************************/
                //1）业务结果明确失败
                if (result.GetValue("err_code").ToString() != "BIZERR_NEED_RETRY" &&
                    result.GetValue("err_code").ToString() != "SYSTEMERROR" &&
                    result.GetValue("err_code").ToString() != "NOTENOUGH")
                {
                    Log.Error("MicroPay", "micropay API interface call success, business failure, result : " + result.ToXml());
                    return result;
                }

                //2) 使用相同退款单号重试
                if (result.GetValue("err_code").ToString() == "NOTENOUGH")
                {
                    use_unsettled_fund = !use_unsettled_fund;
                    Log.Debug("MicroPay", "Switched to use the other fund source for refund, use_unsettled_fund = " + use_unsettled_fund);
                }

                retry_count++;
                if (retry_count <= MAX_REFUND_RETRY_TIMES)
                {
                    Log.Debug("MicroPay", "Micropay refund retry, retry_count : " + retry_count);
                }
                else
                {
                    Log.Error("MicroPay", "Micropay refund max retry times exceeded! Result : " + result.ToXml());
                    return result;
                }
            }

        }

        private static async Task<WxPayData> RequestRefund(
            string transaction_id, 
            string out_trade_no, 
            string total_fee, 
            string refund_fee,
            string out_refund_no,
            bool use_unsettled_fund,
            WxPayConfig config,
            X509Certificate2 certification
            )
        {
            if (config == null)
            {
                throw new WxPayException("微信支付，缺少WxPayConfig！");
            }
            WxPayData data = new WxPayData();
            if (!string.IsNullOrEmpty(transaction_id))//微信订单号存在的条件下，则已微信订单号为准
            {
                data.SetValue("transaction_id", transaction_id);
            }
            else//微信订单号不存在，才根据商户订单号去退款
            {
                data.SetValue("out_trade_no", out_trade_no);
            }

            data.SetValue("total_fee", Convert.ToInt32(Decimal.Parse(total_fee) * 100));//订单总金额
            data.SetValue("refund_fee", Convert.ToInt32(Decimal.Parse(refund_fee) * 100));//退款金额
            data.SetValue("out_refund_no", out_refund_no);//商户退款单号
            data.SetValue("op_user_id", config.MCHID);//操作员，默认为商户号
            if (use_unsettled_fund)
            {
                data.SetValue("refund_account", "REFUND_SOURCE_UNSETTLED_FUNDS");
            }
            else
            {
                data.SetValue("refund_account", "REFUND_SOURCE_RECHARGE_FUNDS");
            }

            WxPayData result = await WxPayApi.Refund(data, config, certification);//提交退款申请给API，接收返回数据
            return result;
        }
    }
}