using Aop.Api.Response;
using Com.Alipay.Domain;
using Aop.Api;
using Aop.Api.Request;
using System.Text;
using System.Threading;
using Com.Alipay.Model;
using Com.Alipay.Business;
using System;
using Newtonsoft.Json;
using System.Threading.Tasks;

namespace Com.Alipay
{
    /// <summary>
    /// AlipayTradePayImpl 的摘要说明
    /// </summary>
    public class AlipayTradeImpl : IAlipayTradeService
    {

  

        IAopClient client = null; 

        public AlipayTradeImpl(string serverUrl, string appId, string merchant_private_key, string format, string version,
     string sign_type, string alipay_public_key, string charset)
        {
            client = new DefaultAopClient(serverUrl, appId, merchant_private_key, format, version,
           sign_type, alipay_public_key, charset);

        }


        #region 接口方法
        public async Task<AlipayF2FPayResult> tradePay(AlipayTradePayContentBuilder builder)
        {               
            AlipayF2FPayResult payResult = new AlipayF2FPayResult();
            try
            {

                AlipayTradePayRequest payRequest = new AlipayTradePayRequest();
                payRequest.BizContent = JsonConvert.SerializeObject(builder);
                //payRequest.BizContent = builder.BuildJson();
                AlipayTradePayResponse payResponse = await client.Execute(payRequest);
                
                //payRequest.SetBizModel("");

                if (payResponse != null)
                {

                    switch (payResponse.Code)
                    {
                        case ResultCode.SUCCESS:
                            break;

                        //返回支付处理中，需要进行轮询
                        case ResultCode.INRROCESS:

                            AlipayTradeQueryResponse queryResponse = await LoopQuery(builder.out_trade_no, 10, 3000);   //用订单号trade_no进行轮询也是可以的。
                            //轮询结束后还是支付处理中，需要调撤销接口
                            if (queryResponse != null)
                            {
                                if (queryResponse.TradeStatus == "WAIT_BUYER_PAY")
                                {
                                    CancelAndRetry(builder.out_trade_no);
                                    payResponse.Code = ResultCode.FAIL;
                                }
                                payResponse = toTradePayResponse(queryResponse);
                            }
                            break;

                        //明确返回业务失败
                        case ResultCode.FAIL:
                            break;

                        //返回系统异常，需要调用一次查询接口，没有返回支付成功的话调用撤销接口撤销交易
                        case ResultCode.ERROR:

                            AlipayTradeQueryResponse queryResponse2 = await sendTradeQuery(builder.out_trade_no);

                            if (queryResponse2 != null)
                            {
                                if (queryResponse2.TradeStatus == TradeStatus.WAIT_BUYER_PAY)
                                {
                                    AlipayTradeCancelResponse cancelResponse = await CancelAndRetry(builder.out_trade_no);
                                    payResponse.Code = ResultCode.FAIL;
                                }

                                payResponse = toTradePayResponse(queryResponse2);

                            }
                            break;

                        default:
                            payResult.response = payResponse;
                            break;
                    }
                    payResult.response = payResponse;
                    return payResult;
                }
                else
                {
                    AlipayTradeQueryResponse queryResponse3 = await sendTradeQuery(builder.out_trade_no);
                    if (queryResponse3 != null)
                    {
                        if (queryResponse3.TradeStatus == TradeStatus.WAIT_BUYER_PAY)
                        {
                            AlipayTradeCancelResponse cancelResponse = await CancelAndRetry(builder.out_trade_no);
                            payResponse.Code = ResultCode.FAIL;
                        }
                        payResponse = toTradePayResponse(queryResponse3);
                    }
                    payResult.response = payResponse;
                    return payResult;
                }
                //return payResult;
            }
            catch(Exception e)
            {

                AlipayTradePayResponse payResponse = new AlipayTradePayResponse();
                payResponse.Code = ResultCode.FAIL;
                payResponse.Body = e.Message;
                payResult.response = payResponse;
                return payResult;
            }
        }

        public async Task<AlipayF2FQueryResult> tradeQuery(string outTradeNo)
        {                
            AlipayF2FQueryResult result = new AlipayF2FQueryResult();
            try
            {

                AlipayTradeQueryContentBuilder build = new AlipayTradeQueryContentBuilder();
                build.out_trade_no = outTradeNo;
                AlipayTradeQueryRequest payRequest = new AlipayTradeQueryRequest();
                payRequest.BizContent = JsonConvert.SerializeObject(build);
                //payRequest.BizContent = build.BuildJson();
                result.response = await client.Execute(payRequest);
                return result;
            }
            catch
            {
                result.response = null;
                return result;
            }
        }


        public async Task<AlipayF2FRefundResult> tradeRefund(AlipayTradeRefundContentBuilder builder)
        {               
            AlipayF2FRefundResult refundResult = new AlipayF2FRefundResult();
            try
            {

                AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
                //refundRequest.BizContent = builder.BuildJson();
                refundRequest.BizContent = JsonConvert.SerializeObject(builder);
                refundResult.response = await client.Execute(refundRequest);
                return refundResult;
            }
            catch
            {
                refundResult.response = null;
                return refundResult;
            }
        }

        public async Task<AlipayF2FPrecreateResult> tradePrecreate(AlipayTradePrecreateContentBuilder builder)
        {               
            AlipayF2FPrecreateResult payResult = new AlipayF2FPrecreateResult();
            try
            {

                AlipayTradePrecreateRequest payRequest = new AlipayTradePrecreateRequest();
                //payRequest.BizContent = builder.BuildJson();
                payRequest.BizContent = JsonConvert.SerializeObject(builder);

                payResult.response = await client.Execute(payRequest);
                return payResult;
            }
            catch
            {
                payResult.response = null;
                return payResult;
            }
        }
		
		/// <summary>
        /// 1.返回支付处理中，轮询订单状态
        /// </summary>
        /// <param name="biz_content"></param>
        /// <returns></returns>
        public async Task<AlipayTradeQueryResponse> tradeLoopQuery(string out_trade_no, int count, int interval)
        {
            AlipayTradeQueryResponse queryResult = new AlipayTradeQueryResponse();
            queryResult.TradeStatus = "TRADE_CLOSED";

            for (int i = 0; i <= count; i++)
            {
                AlipayTradeQueryResponse queryResponse = await sendTradeQuery(out_trade_no);
                if (queryResponse != null && string.Compare(queryResponse.Code, ResultCode.SUCCESS, false) == 0)
                {
                    queryResult = queryResponse;
                    if (queryResult.TradeStatus == "TRADE_FINISHED"
                        || queryResult.TradeStatus == "TRADE_SUCCESS"
                        || queryResult.TradeStatus == "TRADE_CLOSED")
                        return queryResult;
                }
				await Task.Delay(interval);
            }

            return queryResult;

        }

        public async Task<AlipayF2FPrecreateResult> tradePrecreate(AlipayTradePrecreateContentBuilder builder, string notify_url)
        {                
            AlipayF2FPrecreateResult payResult = new AlipayF2FPrecreateResult();
            try
            {
                AlipayTradePrecreateRequest payRequest = new AlipayTradePrecreateRequest();
                //payRequest.BizContent = builder.BuildJson();
                payRequest.BizContent = JsonConvert.SerializeObject(builder);
                payRequest.SetNotifyUrl(notify_url);
                payResult.response = await client.Execute(payRequest);
                return payResult;

            }
            catch
            {
                payResult.response = null;
                return payResult;
            }
        }

        #endregion


        #region 内部方法
        private async Task<AlipayTradeCancelResponse> tradeCancel(string outTradeNo)
        {
            try
            {
                AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
                StringBuilder sb2 = new StringBuilder();
                sb2.Append("{\"out_trade_no\":\"" + outTradeNo + "\"}");
                request.BizContent = sb2.ToString();
                AlipayTradeCancelResponse response = await client.Execute(request);
                return response;
            }
            catch
            {
                return null;
            }

        }

        private AlipayTradePayResponse toTradePayResponse(AlipayTradeQueryResponse queryResponse)
        {
            if (queryResponse == null || queryResponse.Code != ResultCode.SUCCESS)
                return null;
            AlipayTradePayResponse payResponse = new AlipayTradePayResponse();

            if (queryResponse.TradeStatus == TradeStatus.WAIT_BUYER_PAY)
            {
                payResponse.Code = ResultCode.INRROCESS;
            }
            if (queryResponse.TradeStatus == TradeStatus.TRADE_FINISHED
                || queryResponse.TradeStatus == TradeStatus.TRADE_SUCCESS)
            {
                payResponse.Code = ResultCode.SUCCESS;
            }
            if (queryResponse.TradeStatus == TradeStatus.TRADE_CLOSED)
            {
                payResponse.Code = ResultCode.FAIL;
            }

            payResponse.Msg = queryResponse.Msg;
            payResponse.SubCode = queryResponse.SubCode;
            payResponse.SubMsg = queryResponse.SubMsg;
            payResponse.Body = queryResponse.Body;
            payResponse.BuyerLogonId = queryResponse.BuyerLogonId;
            payResponse.FundBillList = queryResponse.FundBillList;
            payResponse.OpenId = queryResponse.OpenId;
            payResponse.OutTradeNo = queryResponse.OutTradeNo;
            payResponse.ReceiptAmount = queryResponse.ReceiptAmount;
            payResponse.TotalAmount = queryResponse.TotalAmount;
            payResponse.TradeNo = queryResponse.TradeNo;


            return payResponse;


        }


        private async Task<AlipayTradeQueryResponse> sendTradeQuery(string outTradeNo)
        {
            try
            {
                AlipayTradeQueryContentBuilder build = new AlipayTradeQueryContentBuilder();
                build.out_trade_no = outTradeNo;
                AlipayTradeQueryRequest payRequest = new AlipayTradeQueryRequest();
                //payRequest.BizContent = build.BuildJson();
                payRequest.BizContent = JsonConvert.SerializeObject(build);
                AlipayTradeQueryResponse payResponse = await client.Execute(payRequest);
                return payResponse;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 1.返回支付处理中，轮询订单状态
        /// 2.本示例中轮询了6次，每次相隔5秒
        /// </summary>
        /// <param name="biz_content"></param>
        /// <returns></returns>
        private async Task<AlipayTradeQueryResponse> LoopQuery(string out_trade_no, int count, int interval)
        {
            AlipayTradeQueryResponse queryResult = null;

            for (int i = 1; i <= count; i++)
            {
                await Task.Delay(interval);
                AlipayTradeQueryResponse queryResponse = await sendTradeQuery(out_trade_no);
                if (queryResponse != null && string.Compare(queryResponse.Code, ResultCode.SUCCESS, false) == 0)
                {
                    queryResult = queryResponse;
                    if (queryResponse.TradeStatus == "TRADE_FINISHED"
                        || queryResponse.TradeStatus == "TRADE_SUCCESS"
                        || queryResponse.TradeStatus == "TRADE_CLOSED")
                        return queryResponse;
                }
            }

            return queryResult;

        }

        /// <summary>
        /// 撤销订单
        /// </summary>
        /// <param name="out_trade_no"></param>
        /// <returns></returns>
        private async Task<AlipayTradeCancelResponse> CancelAndRetry(string out_trade_no)
        {
            AlipayTradeCancelResponse cancelResponse = null;

            cancelResponse = await tradeCancel(out_trade_no);

            //如果撤销失败，新开一个线程重试撤销，不影响主业务
            if (cancelResponse == null || (cancelResponse.Code == ResultCode.FAIL && cancelResponse.RetryFlag == "Y"))
            {
                await Task.Run(() => cancelThreadFunc(out_trade_no));
            }
            return cancelResponse;
        }

        private async Task cancelThreadFunc(object o)
        {
            int RETRYCOUNT = 10;
            int INTERVAL = 10000;

            for (int i = 0; i < RETRYCOUNT; ++i)
            {

                await Task.Delay(INTERVAL);
                AlipayTradeCancelRequest cancelRequest = new AlipayTradeCancelRequest();
                string outTradeNo = o.ToString();
                AlipayTradeCancelResponse cancelResponse = await tradeCancel(outTradeNo);

                if (null != cancelResponse)
                {
                    if (cancelResponse.Code == ResultCode.FAIL)
                    {
                        if (cancelResponse.RetryFlag == "N")
                        {
                            break;
                        }
                    }
                    if ((cancelResponse.Code == ResultCode.SUCCESS))
                    {
                        break;
                    }
                }

                if (i == RETRYCOUNT - 1)
                {
                    /** ！！！！！！！注意！！！！！！！！
                    处理到最后一次，还是未撤销成功，需要在商户数据库中对此单最标记，人工介入处理*/
                }

            }
        }

        #endregion
    }
}