package cn.com.ty.lift.ud.pay.controller;

import cn.com.ty.lift.ud.chat.mapper.entity.ChatSessionEntity;
import cn.com.ty.lift.ud.chat.mapper.entity.LiftCaseEntity;
import cn.com.ty.lift.ud.chat.service.IChatSessionService;
import cn.com.ty.lift.ud.chat.service.ILiftCaseService;
import cn.com.ty.lift.ud.common.RandomizingID;
import cn.com.ty.lift.ud.operation.mapper.entity.CommissionSettingEntity;
import cn.com.ty.lift.ud.operation.mapper.entity.UserLevelRuleEntity;
import cn.com.ty.lift.ud.operation.mapper.entity.UserRebateRuleEntity;
import cn.com.ty.lift.ud.operation.mapper.entity.VipFeeSettingEntity;
import cn.com.ty.lift.ud.operation.service.ICommissionSettingService;
import cn.com.ty.lift.ud.operation.service.IUserLevelRuleService;
import cn.com.ty.lift.ud.operation.service.IUserRebateRuleService;
import cn.com.ty.lift.ud.operation.service.IVipFeeSettingService;
import cn.com.ty.lift.ud.pay.alipay.AlipayConfig;
import cn.com.ty.lift.ud.pay.alipay.AlipaySupport;
import cn.com.ty.lift.ud.pay.controller.req.PassbackParamsDTO;
import cn.com.ty.lift.ud.pay.controller.req.PayDTO;
import cn.com.ty.lift.ud.pay.enums.IdentityType;
import cn.com.ty.lift.ud.pay.enums.PassbackEnum;
import cn.com.ty.lift.ud.pay.service.AlipayService;
import cn.com.ty.lift.ud.payment.mapper.entity.TyBillEntity;
import cn.com.ty.lift.ud.payment.mapper.entity.UserBillEntity;
import cn.com.ty.lift.ud.payment.mapper.entity.UserRechargeDetailEntity;
import cn.com.ty.lift.ud.payment.mapper.entity.UserWithdrawEntity;
import cn.com.ty.lift.ud.payment.service.ITyBillService;
import cn.com.ty.lift.ud.payment.service.IUserBillService;
import cn.com.ty.lift.ud.payment.service.IUserRechargeDetailService;
import cn.com.ty.lift.ud.payment.service.IUserWithdrawService;
import cn.com.ty.lift.ud.question.mapper.QuestionBankMapper;
import cn.com.ty.lift.ud.question.mapper.entity.QuestionBankEntity;
import cn.com.ty.lift.ud.question.mapper.entity.QuestionOperateEntity;
import cn.com.ty.lift.ud.question.service.IQuestionOperateService;
import cn.com.ty.lift.ud.schoolVideo.mapper.entity.SchoolVideoEntity;
import cn.com.ty.lift.ud.schoolVideo.mapper.entity.SchoolVideoOperateEntity;
import cn.com.ty.lift.ud.schoolVideo.service.ISchoolVideoOperateService;
import cn.com.ty.lift.ud.schoolVideo.service.ISchoolVideoService;
import cn.com.ty.lift.ud.tableDict.service.ITableDictService;
import cn.com.ty.lift.ud.userAccount.mapper.entity.UserAccount;
import cn.com.ty.lift.ud.userAccount.service.IUserAccountService;
import cn.com.ty.lift.ud.userInfo.mapper.UserInfoMapper;
import cn.com.ty.lift.ud.userInfo.mapper.entity.UserInfoEntity;
import cn.com.ty.lift.ud.userInfo.service.IUserInfoService;
import cn.com.ty.lift.ud.userRebate.mapper.entity.UserRebateEntity;
import cn.com.ty.lift.ud.userRebate.service.IUserRebateService;
import cn.com.ty.lift.ud.utils.QrCodeUtil;
import cn.com.ty.lift.ud.utils.UUIDUtil;
import cn.com.xwy.boot.web.dto.RestResponse;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.file.Charsets;
import com.alipay.api.internal.util.file.FileUtils;
import com.alipay.api.request.AlipayDataBillBalanceQueryRequest;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayDataBillBalanceQueryResponse;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.netty.channel.Channel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 支付宝前端控制器
 * 
 * @author IyesKing
 * @date 2020年5月15日
 */
@Slf4j
@Api(tags = "支付宝V2.0- 盛文静")
@RestController
@RequestMapping("/api")
public class AlipayController {

    private @Autowired AlipayConfig alipayConfig;

    private @Autowired AlipaySupport alipaySupport;

    private @Autowired ILiftCaseService liftCaseService;

    private @Autowired IChatSessionService chatSessionService;

    private @Autowired IUserBillService userBillService;

    private @Autowired IUserRechargeDetailService userRechargeDetailService;

    private @Autowired IUserInfoService userInfo;

    private @Autowired QuestionBankMapper questionBankMapper;

    private @Autowired IQuestionOperateService iQuestionOperateService;

    private @Autowired ICommissionSettingService iCommissionSettingService;

    private @Autowired IUserBillService iUserBillService;

    private @Autowired ITyBillService iTyBillService;

    private @Autowired ISchoolVideoOperateService schoolVideoOperateService;

    private @Autowired ISchoolVideoService schoolVideoService;

    private @Autowired ITableDictService tableDictService;

    private @Autowired IVipFeeSettingService vipFeeSettingService;

    private @Autowired IUserRebateService iUserRebateService;

    private @Autowired UserInfoMapper userInfoMapper;

    private @Autowired IUserLevelRuleService iUserLevelRuleService;

    private @Autowired IUserWithdrawService userWithdrawService;

    @Autowired
    private IUserAccountService iUserAccountService;

    @Autowired
    private IUserRebateRuleService iUserRebateRuleService;

    @Autowired
    private AlipayService alipayService;

    /**
     * 支付宝-电脑网站支付
     * 
     * @param response
     * @param money
     * @param outTradeNo
     */
    @ApiOperation("支付宝-电脑网站支付")
    @GetMapping("/alipay/pc")
    public void alipayPc(HttpServletResponse response, @RequestParam("money") String money,
        @RequestParam("outTradeNo") String outTradeNo) {
        log.info("====进入【支付宝-电脑网站支付】====");
        if (StringUtils.isBlank(money) || StringUtils.isBlank(outTradeNo)) {
            log.error("支付金额、订单号参数不能为空。");
            return;
        }
        double moneyDou = Double.parseDouble(money);
        if (moneyDou <= 0) {
            // 金额无效
            log.error("支付金额无效");
            return;
        }

        // PC场景下单并支付接口，请求参数。
        AlipayTradePagePayModel tradePagePayModel = new AlipayTradePagePayModel();
        tradePagePayModel.setOutTradeNo(outTradeNo);
        tradePagePayModel.setTotalAmount(money);
        tradePagePayModel.setProductCode("FAST_INSTANT_TRADE_PAY");
        tradePagePayModel.setSubject(alipayConfig.getSubjectName());

        // 设置支付宝异步回调接口地址
        String notifyUrl = alipayConfig.getAlipayNotifyUrl();
        try {
            // 下单并输出表单。
            alipaySupport.tradePagePay(response, tradePagePayModel, notifyUrl, null);
        } catch (AlipayApiException e) {
            log.error("调用SDK生成表单时发生异常");
            log.error(e.getMessage());
            return;
        } catch (IOException e) {
            log.error("输出表单时发生IO异常");
            log.error(e.getMessage());
        }
    }

    /**
     * 支付宝-诊单APP支付
     * 
     * @param pay
     *            订单对象
     * @return
     */
    @ApiOperation("APP支付宝-诊单支付")
    @PostMapping("/alipay")
    public RestResponse alipayApp(@RequestBody PayDTO pay) {
        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("订单号不能为空。");
            return RestResponse.fail("0", "订单号不能为空。");
        }

        if (null == pay.getLiftCaseType()) {
            log.error("出诊问诊类型不能为空。");
            return RestResponse.fail("0", "出诊问诊类型不能为空。");
        }

        QueryWrapper<LiftCaseEntity> queryWrapper = new QueryWrapper<LiftCaseEntity>();
        queryWrapper.eq("order_no", pay.getOrders());
        LiftCaseEntity orders = liftCaseService.getOne(queryWrapper);

        if (null == orders) {
            log.error("该支付订单不存在请检查！");
            return RestResponse.fail("0", "该支付订单不存在请检查！");
        }

        try {
            BigDecimal totalAmount = orders.getPayCost();

            if (totalAmount.compareTo(new BigDecimal("0.01")) == -1) {
                log.info("所需支付金额为：{}元,无需调用支付宝。走余额支付回调", totalAmount);
                return RestResponse.fail("0", "该订单支付金额小于0.01元，请使用余额支付！");
            }

            // APP支付请求参数。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setOutTradeNo(pay.getOrders());
            model.setTotalAmount(totalAmount.toString());
            model.setProductCode("QUICK_MSECURITY_PAY");
            model.setSubject(alipayConfig.getSubjectName());
            // 公用回传参数
            String passbackParams = "";
            if (pay.getLiftCaseType() == 1) {
                if (0 != orders.getStatuz()) {
                    if (8 != orders.getStatuz()) {
                        log.error("该支付订单状态有误请检查！");
                        return RestResponse.fail("0", "该支付订单状态有误请检查！");
                    }
                }
                passbackParams = assemblePassbackParams(PassbackEnum.LIFT_CASE_PAY.getCode(), "问诊订单回调", null, null);
            } else if (pay.getLiftCaseType() == 2) {
                if (2 != orders.getStatuz()) {
                    if (8 != orders.getStatuz()) {
                        log.error("该支付订单状态有误请检查！");
                        return RestResponse.fail("0", "该支付订单状态有误请检查！");
                    }
                }
                passbackParams = assemblePassbackParams(PassbackEnum.LIFT_CALL_PAY.getCode(), "出诊订单回调", null, null);
            } else {
                log.error("出诊问诊类型有误。");
                return RestResponse.fail("0", "出诊问诊类型有误。");
            }

            model.setPassbackParams(passbackParams);

            // 设置支付宝异步回调接口地址
            String notifyUrl = alipayConfig.getAlipayNotifyUrl();
            log.info("notifyUrl:{}", notifyUrl);
            // 调用SDK去支付。
            String getBody = alipaySupport.tradeAppPay(model, notifyUrl);
            return RestResponse.success(getBody, "success");
        } catch (AlipayApiException e) {
            log.error("调用APP支付接口时发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        } catch (UnsupportedEncodingException e) {
            log.error("调用URLEncoder编码发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        }
    }

    /**
     * 支付宝-打赏APP支付
     * 
     * @param pay
     *            订单对象
     * @return
     */
    @ApiOperation("APP支付宝-打赏支付")
    @PostMapping("/reward")
    public RestResponse rewardApp(@RequestBody PayDTO pay) {
        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("订单号参数不能为空。");
            return RestResponse.fail("0", "订单号不能为空。");
        }

        if (null == pay.getUserId()) {
            log.error("打赏用户id不能为空。");
            return RestResponse.fail("0", "打赏用户id不能为空。");
        }

        if (null == pay.getRewardType()) {
            log.error("打赏类型不能为空。");
            return RestResponse.fail("0", "打赏类型能为空。");
        }

        if (null == pay.getReawrdMoney()) {
            log.error("打赏代号不能为空。");
            return RestResponse.fail("0", "打赏代号能为空。");
        }
        try {
            // 打赏金额
            String totalAmount = tableDictService.findOneByTableAndColumnAndCode("reward_setting", "reward", pay.getReawrdMoney().getCode());
            if (StringUtils.isBlank(totalAmount)) {
                log.error("打赏代号有误。");
                return RestResponse.fail("0", "打赏代号有误。");
            }

            // 公用回传参数
            String passbackParams = "";
            if (1 == pay.getRewardType()) {
                QueryWrapper<QuestionBankEntity> queryWrapper = new QueryWrapper<QuestionBankEntity>();
                queryWrapper.eq("id", pay.getOrders());
                QuestionBankEntity orders = questionBankMapper.selectOne(queryWrapper);
                if (null == orders) {
                    log.error("打赏题库不存在请检查！");
                    return RestResponse.fail("0", "打赏题库不存在请检查！");
                }
                // totalAmount = orders.getReward();
                passbackParams = assemblePassbackParams(PassbackEnum.REWARD_PAY.getCode(), "题库打赏", pay.getUserId(), pay.getOrders());
            } else if (2 == pay.getRewardType()) {
                QueryWrapper<SchoolVideoEntity> queryWrapper = new QueryWrapper<SchoolVideoEntity>();
                queryWrapper.eq("id", pay.getOrders());
                SchoolVideoEntity orders = schoolVideoService.getOne(queryWrapper);

                if (null == orders) {
                    log.error("打赏视频不存在请检查！");
                    return RestResponse.fail("0", "打赏视频不存在请检查！");
                }
                // totalAmount = orders.getReward();
                passbackParams = assemblePassbackParams(PassbackEnum.VIDEO_PAY.getCode(), "视频打赏", pay.getUserId(), pay.getOrders());
            } else {
                log.error("打赏类型有误。");
                return RestResponse.fail("0", "打赏类型有误。");
            }

            // APP支付请求参数。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setOutTradeNo(UUIDUtil.getUuidByTime(8));
            model.setTotalAmount(totalAmount);
            model.setProductCode("QUICK_MSECURITY_PAY");
            model.setSubject(alipayConfig.getSubjectName());

            model.setPassbackParams(passbackParams);

            // 设置支付宝异步回调接口地址
            String notifyUrl = alipayConfig.getAlipayNotifyUrl();
            log.info("notifyUrl:{}", notifyUrl);
            // 调用SDK去支付。
            String getBody = alipaySupport.tradeAppPay(model, notifyUrl);
            return RestResponse.success(getBody, "success");
        } catch (AlipayApiException e) {
            log.error("调用APP支付接口时发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        } catch (UnsupportedEncodingException e) {
            log.error("调用URLEncoder编码发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        }
    }

    /**
     * APP支付宝-查询商户余额
     * 
     * @return
     */
    @ApiOperation("APP支付宝-查询商户余额")
    @PostMapping("/balanceQuery")
    public RestResponse balanceQuery() {
        try {

            AlipayDataBillBalanceQueryRequest request = new AlipayDataBillBalanceQueryRequest();
            // 调用SDK去支付。
            AlipayDataBillBalanceQueryResponse getBody = alipaySupport.balanceQuery(request);
            return RestResponse.success(getBody, "success");
        } catch (AlipayApiException e) {
            log.error("调用APP支付接口时发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        }
    }

    /**
     * 支付宝-APP用户充值
     * 
     * @param pay
     *            订单对象
     * @return
     */
    @ApiOperation("支付宝-APP用户充值")
    @PostMapping("/alipayRecharge")
    public RestResponse apyRechargeApp(@RequestBody PayDTO pay) {
        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("请输入订单号.");
            return RestResponse.fail("0", "请输入订单号.");
        }

        try {
            QueryWrapper<UserRechargeDetailEntity> queryWrapper = new QueryWrapper<UserRechargeDetailEntity>();
            queryWrapper.eq("order_sn", pay.getOrders());
            UserRechargeDetailEntity rechargeDetail = userRechargeDetailService.getOne(queryWrapper);

            if (null == rechargeDetail) {
                return RestResponse.fail("0", "无效的充值，请重试");
            }

            if (1 != rechargeDetail.getPayStatus()) {
                return RestResponse.fail("0", "充值状态有误，请重试");
            }

            // 充值金额
            BigDecimal rechargeAmount = rechargeDetail.getProductPrice();

            // TODO 上线取消下面注释
            /*if (rechargeAmount.compareTo(BigDecimal.ONE) == -1) {
                logger.error("支付金额不小于壹元(RMB)。");
                return RestResponse.fail("0", "支付金额不小于壹元(RMB)。");
            }*/
            // APP支付请求参数。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setOutTradeNo(pay.getOrders());
            model.setTotalAmount(rechargeAmount.toString());
            model.setProductCode("QUICK_MSECURITY_PAY");
            model.setSubject(alipayConfig.getSubjectName());
            // 公用回传参数
            String passbackParams =
                assemblePassbackParams(PassbackEnum.RECHARGE_PAY.getCode(), "用户充值", rechargeDetail.getUserId(), null);
            model.setPassbackParams(passbackParams);

            // 设置支付宝异步回调接口地址
            String notifyUrl = alipayConfig.getAlipayNotifyUrl();
            log.info("notifyUrl:{}", notifyUrl);
            // 调用SDK去支付。
            String getBody = alipaySupport.tradeAppPay(model, notifyUrl);
            return RestResponse.success(getBody, "success");
        } catch (AlipayApiException e) {
            log.error("调用APP支付接口时发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        } catch (UnsupportedEncodingException e) {
            log.error("调用URLEncoder编码发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        }
    }

    /**
     * 支付宝-WEB提现打款
     * 
     * @param pay
     *            订单对象
     * @return
     */
//    @CrossOrigin
    @ApiOperation("支付宝-WEB提现打款")
    @PostMapping("/withdrawMoney")
    public RestResponse withdrawMoney(@RequestBody PayDTO pay) {
        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("请输入订单号.");
            return RestResponse.fail("0", "请输入订单号.");
        }

        try {
            QueryWrapper<UserWithdrawEntity> queryWrapper = new QueryWrapper<UserWithdrawEntity>();
            queryWrapper.eq("orders", pay.getOrders());
            UserWithdrawEntity rechargeDetail = userWithdrawService.getOne(queryWrapper);

            if (null == rechargeDetail) {
                return RestResponse.fail("0", "无效的提现记录。");
            }

            if (1 != rechargeDetail.getStatuz()) {
                return RestResponse.fail("0", "提现记录状态有误。");
            }

            // 提现金额
            BigDecimal rechargeAmount = rechargeDetail.getAmount();

            // APP支付请求参数。
            AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
            model.setOutBizNo(pay.getOrders());
            model.setProductCode("TRANS_ACCOUNT_NO_PWD");
            model.setBizScene("DIRECT_TRANSFER");

            Participant participant = new Participant();
            participant.setIdentity(rechargeDetail.getAcount());// 转到账户
            participant.setIdentityType(IdentityType.ALIPAY_LOGON_ID.getCode());
            participant.setName(rechargeDetail.getName());// 参与方真实姓名，如果非空，将校验收款支付宝账号姓名一致性。当identity_type=ALIPAY_LOGON_ID时，本字段必填。
            model.setPayeeInfo(participant);
            model.setTransAmount(rechargeAmount.toString());
            model.setRemark("单笔转账到支付宝");

            AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
            request.setBizModel(model);
            String appCert = AlipaySignature.getCertSN(alipayConfig.getAppCertPath());
            String apppayRootCert =
                FileUtils.readFileToString(new File(alipayConfig.getAlipayRootCertPath()), Charsets.toCharset("utf-8"));

            // 这里必须添加 app公匙证书的序列号和阿里根证书的序列号
            request.putOtherTextParam("app_cert_sn", appCert);
            request.putOtherTextParam("alipay_root_cert_sn", apppayRootCert);

            QueryWrapper<UserInfoEntity> userQueryWrapper = new QueryWrapper<UserInfoEntity>();
            userQueryWrapper.eq("user_id", rechargeDetail.getUserId());
            UserInfoEntity user = userInfo.getOne(userQueryWrapper);

            // 调用SDK去支付。
            AlipayFundTransUniTransferResponse alipayFundTrans = alipaySupport.transfer(request);
            LocalDateTime toDay = LocalDateTime.now();
            if (alipayFundTrans.isSuccess() && alipayFundTrans.getStatus().equals("SUCCESS")) {

                // 状态 0:申请1:审核通过2:提现3:提现成功4、审核不通过5、提现失败6、提现处理中7、退票
                rechargeDetail.setStatuz(3);

//                // 组装用户流水记录
//                UserBillEntity entity = new UserBillEntity();
//                entity.setAmount(rechargeAmount);
//                entity.setCreateTime(toDay);
//                entity.setUserId(user.getUserId());
//                entity.setFlowNum(alipayFundTrans.getPayFundOrderId());
//                entity.setType(1);// '交易类型 1：支出、2：收入
//                entity.setBusinessType(5); // 业务类型：如：2 打赏，3 充值，1 充值会员 4服务费、5提现
//                entity.setDescr("用户提现");
//                entity.setBalance(user.getBalance().subtract(rechargeAmount));
//                userBillService.save(entity);

                log.info("--- 提现的平台流水开始 ---");
                // 记录平台流水
                TyBillEntity tyBill = new TyBillEntity();
                tyBill.setAmount(rechargeAmount);
                tyBill.setCreateTime(toDay);
                tyBill.setUserId(user.getUserId());
                tyBill.setFlowNum(alipayFundTrans.getPayFundOrderId());
                tyBill.setType(1);
                tyBill.setBusinessType(5);
                tyBill.setDescr("用户提现");
                BigDecimal balance = iTyBillService.getLatestBalance();
                tyBill.setBalance(balance.subtract(rechargeAmount));
                iTyBillService.save(tyBill);
                log.info("--- 提现的平台流水结束 ---");

                //根据订单号找到之前的 用户流水记录，把支付宝的流水号更新到用户流水中
                UserBillEntity billEntity = userBillService.getByFlowNum(pay.getOrders());
                if(null != billEntity){
                    billEntity.setFlowNum(alipayFundTrans.getPayFundOrderId());
                    userBillService.updateById(billEntity);
                }

            } else {
                rechargeDetail.setStatuz(5);
                // 提现失败退回提现金额到余额
                userInfo.rechargePayBalance(Long.valueOf(rechargeDetail.getUserId()), rechargeAmount);

                // 组装用户流水记录
                UserBillEntity entity = new UserBillEntity();
                entity.setAmount(rechargeAmount);
                entity.setCreateTime(toDay);
                entity.setUserId(user.getUserId());
                entity.setTargetUserId(1L);
                entity.setFlowNum(alipayFundTrans.getPayFundOrderId());
                entity.setType(2);// '交易类型 1：支出、2：收入
                entity.setBusinessType(6); // 业务类型：如：2 打赏，3 充值，1 充值会员 4服务费、5提现、6提现失败退款
                entity.setDescr("提现失败，金额已返还至钱包");
                entity.setBalance(user.getBalance().add(rechargeAmount));
                userBillService.save(entity);
            }

            String message = "";
            if ("10000".equals(alipayFundTrans.getCode())) {
                message = "提现成功";
            } else {
                message = alipayFundTrans.getSubMsg();
            }
            rechargeDetail.setTradNo(alipayFundTrans.getPayFundOrderId());
            rechargeDetail.setMome(message);
            userWithdrawService.update(rechargeDetail, queryWrapper);

            return RestResponse.success("1", message);
        } catch (AlipayApiException e) {
            log.error("调用提现接口时发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用提现接口时发生异常");
        } catch (IOException e) {
            log.error("提现出现异常，读取app公匙证书的序列号和阿里根证书的序列号出错");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用提现接口时发生异常");
        }
    }

    /**
     * 支付宝-充值成为VIP用户
     * 
     * @param pay
     *            订单对象
     * @return
     */
    @ApiOperation("APP支付宝-充值成为VIP用户")
    @PostMapping("/rechargeVIP")
    public RestResponse rechargeVIP(@RequestBody PayDTO pay) {
        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("订单号不能为空。");
            return RestResponse.fail("0", "订单号不能为空。");
        }

        if (null == pay.getUserId()) {
            log.error("打赏用户id不能为空。");
            return RestResponse.fail("0", "打赏用户id不能为空。");
        }

        QueryWrapper<VipFeeSettingEntity> queryWrapper = new QueryWrapper<VipFeeSettingEntity>();
        queryWrapper.eq("id", pay.getOrders());
        VipFeeSettingEntity orders = vipFeeSettingService.getOne(queryWrapper);

        if (null == orders) {
            log.error("该项会费不存在请检查！");
            return RestResponse.fail("0", "该项会费不存在请检查！");
        }

        /** 0 待审核 1 审核通过 2 驳回 3 待提交 */
        final int flag = 1;
        if (flag != orders.getExamineFlag()) {
            log.error("该项会费不支持使用请检查！");
            return RestResponse.fail("0", "该项会费不支持使用请检查！");
        }

        UserInfoEntity userInfoEntity = userInfoMapper.getByUserId(pay.getUserId());
        if (null == userInfoEntity) {
            log.error("当前用户不存在");
            return RestResponse.fail("当前用户不存在");
        }
        UserLevelRuleEntity userLevelRole = iUserLevelRuleService.getById(orders.getUserLevelId());
        if (null == userLevelRole) {
            log.error("当前会员角色等级不存在，请检查");
            return RestResponse.fail("当前会员角色等级不存在，请检查");
        }

        try {
            BigDecimal totalAmount = orders.getPrice();

            // APP支付请求参数。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setOutTradeNo(UUIDUtil.getUuidByTime(8));
            model.setTotalAmount(totalAmount.toString());
            model.setProductCode("QUICK_MSECURITY_PAY");
            model.setSubject(alipayConfig.getSubjectName());
            // 公用回传参数
            String passbackParams = assemblePassbackParams(PassbackEnum.RECHARGE_VIP_PAY.getCode(), orders.getName(),
                pay.getUserId(), orders.getId().toString());

            model.setPassbackParams(passbackParams);

            // 设置支付宝异步回调接口地址
            String notifyUrl = alipayConfig.getAlipayNotifyUrl();
            log.info("notifyUrl:{}", notifyUrl);
            // 调用SDK去支付。
            String getBody = alipaySupport.tradeAppPay(model, notifyUrl);
            return RestResponse.success(getBody, "success");
        } catch (AlipayApiException e) {
            log.error("调用APP支付接口时发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        } catch (UnsupportedEncodingException e) {
            log.error("调用URLEncoder编码发生异常");
            log.error(e.getMessage());
            return RestResponse.fail("0", "调用APP支付接口时发生异常");
        }
    }

    /**
     * 平台账户余额支付
     * 
     * @param pay
     *            订单对象
     * @return
     */
    @ApiOperation("平台账户余额支付")
    @PostMapping("/alipayBalanceApp")
    public RestResponse alipayBalanceApp(@RequestBody PayDTO pay) {

        if (null == pay.getPayType()) {
            log.error("余额支付类型不能为空。");
            return RestResponse.fail("0", "余额支付类型不能为空。");
        }

        // try {
        // 余额支付类型：CASE(问诊)，CALL(出诊)，QUESTION（题库），VIDEO(s视频)
        if (pay.getPayType().equals("CASE")) {
            return casetoBalance(pay);
        } else if (pay.getPayType().equals("CALL")) {
            return callToBalance(pay);
        } else if (pay.getPayType().equals("QUESTION")) {
            return questionToBalance(pay);
        } else if (pay.getPayType().equals("VIDEO")) {
            return videoToBalance(pay);
        } else {
            log.error("余额支付类型有误。");
            return RestResponse.fail("0", "余额支付类型有误。");
        }

        // } catch (Exception e) {
        // log.error("调用余额支付接口时发生异常");
        // log.error(e.getMessage());
        // return RestResponse.fail("0", "余额支付发生错误");
        // }
    }

    /**
     * 余额打赏视频
     * 
     * @param pay
     * @return
     */
    private RestResponse videoToBalance(PayDTO pay) {

        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("订单号不能为空。");
            return RestResponse.fail("0", "订单号不能为空。");
        }

        QueryWrapper<SchoolVideoEntity> videoQueryWrapper = new QueryWrapper<SchoolVideoEntity>();
        videoQueryWrapper.eq("id", pay.getOrders());
        SchoolVideoEntity orders = schoolVideoService.getOne(videoQueryWrapper);

        if (null == orders) {
            log.error("打赏视频不存在请检查！");
            return RestResponse.fail("0", "打赏视频不存在请检查！");
        }

        if (null == pay.getUserId()) {
            log.error("打赏用户id不能为空。");
            return RestResponse.fail("0", "打赏用户id不能为空。");
        }

        if (null == pay.getReawrdMoney()) {
            log.error("打赏代号不能为空。");
            return RestResponse.fail("0", "打赏代号能为空。");
        }
        // 打赏金额
        String videoAmount =
            tableDictService.findOneByTableAndColumnAndCode("reward_setting", "reward", pay.getReawrdMoney().getCode());
        if (StringUtils.isBlank(videoAmount)) {
            log.error("打赏代号有误。");
            return RestResponse.fail("0", "打赏代号有误。");
        }

        // 更新账户余额
        QueryWrapper<UserInfoEntity> userInfoWrapper = new QueryWrapper<>();
        Long userId = pay.getUserId();
        userInfoWrapper.eq("user_id", userId);
        UserInfoEntity users = userInfo.getOne(userInfoWrapper);
        BigDecimal totalAmount = new BigDecimal(videoAmount);
        if (users.getBalance().compareTo(totalAmount) == -1) {
            log.error("余额不足。");
            return RestResponse.fail("0", "余额不足。");
        }

        String billId = RandomizingID.getBillId();
        alipayService.videoPaymentComplete(orders.getId(), pay.getUserId(), billId, videoAmount, 2);

        return RestResponse.success("SUCCESS");
    }

    /**
     * 余额打赏题库
     * 
     * @param pay
     * @return
     */
    private RestResponse questionToBalance(PayDTO pay) {

        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("订单号不能为空。");
            return RestResponse.fail("0", "订单号不能为空。");
        }

        QueryWrapper<QuestionBankEntity> questionQueryWrapper = new QueryWrapper<QuestionBankEntity>();
        questionQueryWrapper.eq("id", pay.getOrders());
        QuestionBankEntity orders = questionBankMapper.selectOne(questionQueryWrapper);
        if (null == orders) {
            log.error("打赏题库不存在请检查！");
            return RestResponse.fail("0", "打赏题库不存在请检查！");
        }
        if (null == pay.getUserId()) {
            log.error("打赏用户id不能为空。");
            return RestResponse.fail("0", "打赏用户id不能为空。");
        }

        if (null == pay.getReawrdMoney()) {
            log.error("打赏代号不能为空。");
            return RestResponse.fail("0", "打赏代号能为空。");
        }
        // 打赏金额
        String questionAmount =
            tableDictService.findOneByTableAndColumnAndCode("reward_setting", "reward", pay.getReawrdMoney().getCode());
        if (StringUtils.isBlank(questionAmount)) {
            log.error("打赏代号有误。");
            return RestResponse.fail("0", "打赏代号有误。");
        }

        // 更新账户余额
        QueryWrapper<UserInfoEntity> userInfoWrapper = new QueryWrapper<>();
        Long userId = pay.getUserId();
        userInfoWrapper.eq("user_id", userId);
        UserInfoEntity users = userInfo.getOne(userInfoWrapper);
        BigDecimal totalAmount = new BigDecimal(questionAmount);
        if (users.getBalance().compareTo(totalAmount) == -1) {
            log.error("余额不足。");
            return RestResponse.fail("0", "余额不足。");
        }

        // 生成流水号
        String billId = RandomizingID.getBillId();
        alipayService.questionPaymentComplete(orders.getId(), pay.getUserId(), billId, questionAmount, 2);

        return RestResponse.success("SUCCESS");
    }

    /**
     * 余额支付出诊
     * 
     * @param pay
     * @return
     */
    private RestResponse callToBalance(PayDTO pay) {
        BigDecimal totalAmount;
        QueryWrapper<LiftCaseEntity> queryWrapper = new QueryWrapper<LiftCaseEntity>();
        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("订单号不能为空。");
            return RestResponse.fail("0", "订单号不能为空。");
        }

        queryWrapper.eq("order_no", pay.getOrders());
        LiftCaseEntity orders = liftCaseService.getOne(queryWrapper);
        if (null == orders) {
            log.error("该支付订单不存在请检查！");
            return RestResponse.fail("0", "该支付订单不存在请检查！");
        }
        totalAmount = orders.getPayCost();
        if (2 != orders.getStatuz()) {
            if (8 != orders.getStatuz()) {
                log.error("该支付订单状态有误请检查！");
                return RestResponse.fail("0", "该支付订单状态有误请检查！");
            }
        }

        // 更新账户余额
        QueryWrapper<UserInfoEntity> userInfoWrapper = new QueryWrapper<>();
        Long userId = orders.getCreateUserId();
        userInfoWrapper.eq("user_id", userId);
        UserInfoEntity users = userInfo.getOne(userInfoWrapper);
        if (users.getBalance().compareTo(totalAmount) == -1) {
            log.error("余额不足。");
            return RestResponse.fail("0", "余额不足。");
        }

        String billId = RandomizingID.getBillId();
        alipayService.yeCallPaymentComplete(pay.getOrders(), totalAmount.toString(), billId, userId);

        return RestResponse.success("SUCCESS");
    }

    /**
     * 余额支付问诊
     * 
     * @param pay
     * @return
     */
    private RestResponse casetoBalance(PayDTO pay) {
        if (StringUtils.isBlank(pay.getOrders())) {
            log.error("订单号不能为空。");
            return RestResponse.fail("0", "订单号不能为空。");
        }
        BigDecimal totalAmount;
        QueryWrapper<LiftCaseEntity> queryWrapper = new QueryWrapper<LiftCaseEntity>();

        queryWrapper.eq("order_no", pay.getOrders());

        LiftCaseEntity orders = liftCaseService.getOne(queryWrapper);
        if (null == orders) {
            log.error("该支付订单不存在请检查！");
            return RestResponse.fail("0", "该支付订单不存在请检查！");
        }
        totalAmount = orders.getPayCost();
        if (0 != orders.getStatuz()) {
            if (8 != orders.getStatuz()) {
                log.error("该支付订单状态有误请检查！");
                return RestResponse.fail("0", "该支付订单状态有误请检查！");
            }
        }

        // 更新账户余额
        QueryWrapper<UserInfoEntity> userInfoWrapper = new QueryWrapper<>();
        Long userId = orders.getCreateUserId();
        userInfoWrapper.eq("user_id", userId);
        UserInfoEntity users = userInfo.getOne(userInfoWrapper);
        if (users.getBalance().compareTo(totalAmount) == -1) {
            log.error("余额不足。");
            return RestResponse.fail("0", "余额不足。");
        }
        String billId = RandomizingID.getBillId();
        alipayService.yeCasePaymentComplete(pay.getOrders(), totalAmount.toString(), billId, userId);

        return RestResponse.success("SUCCESS");
    }

    /**
     * app支付回调
     * 
     * @param response
     * @param request
     * @return 支付相关信息
     */
    @ApiOperation("app支付回调")
    @ApiIgnore
    @RequestMapping(value = "/alipayNotify", method = RequestMethod.POST)
    public String alipayNotify(HttpServletResponse response, HttpServletRequest request) {
        Map<String, String> params = alipayParamsMap(request);

        log.info("《====支付宝回调=====》:{}", params);

        // 获取验签结果
        boolean signVerified = alipaySignVerifiedResult(params, alipayConfig.getAlipayCertPath());

        if (signVerified) {
            // appId
            String alipayAppId = alipayConfig.getAppid();

            log.info("支付宝验签成功");
            // 校验APP_ID
            String appId = params.get("app_id");
            if (!alipayAppId.equalsIgnoreCase(appId)) {
                log.error("支付宝APP_ID校验失败");
                return "fail";
            }
            try {
                // 拿到订单号、金额以及支付宝流水号
                String outTradeNo = params.get("out_trade_no");
                String totalAmount = params.get("total_amount");
                String tradeNo = params.get("trade_no");

                // 拿到公共回传参数
                String passbackParams = params.get("passback_params");
                passbackParams = URLDecoder.decode(passbackParams, "UTF-8");
                PassbackParamsDTO dto = JSON.parseObject(passbackParams, PassbackParamsDTO.class);

                // 重新查询支付宝订单，再判断交易状态。
                boolean tradeStatus = alipaySupport.tradeQuery(tradeNo, outTradeNo);

                // 判断交易状态
                if (tradeStatus) {

                    log.info("支付宝APP支付，交易成功，即将处理的业务代码：{}", dto.getMemo());

                    if (dto.getType() == PassbackEnum.LIFT_CASE_PAY.getCode()) {
                        alipayService.zfbCasePaymentComplete(outTradeNo, totalAmount, tradeNo);
                    } else if (dto.getType() == PassbackEnum.RECHARGE_PAY.getCode()) {
                        alipayService.rechargePay(outTradeNo, totalAmount, tradeNo, dto);
                    } else if (dto.getType() == PassbackEnum.LIFT_CALL_PAY.getCode()) {
                        alipayService.zfbCallPaymentComplete(outTradeNo, totalAmount, tradeNo);
                    } else if (dto.getType() == PassbackEnum.REWARD_PAY.getCode()) {
                        Long questionId = Long.valueOf(dto.getDataId());
                        alipayService.questionPaymentComplete(questionId, dto.getUserId(), tradeNo, totalAmount, 1);
                    } else if (dto.getType() == PassbackEnum.VIDEO_PAY.getCode()) {
                        Long videoId = Long.valueOf(dto.getDataId());
                        alipayService.videoPaymentComplete(videoId, dto.getUserId(), tradeNo, totalAmount, 1);
                    } else if (dto.getType() == PassbackEnum.RECHARGE_VIP_PAY.getCode()) {
                        Long vipFeeSetting = Long.valueOf(dto.getDataId());
                        alipayService.toVIPPaymentComplete(vipFeeSetting, dto.getUserId(), tradeNo, totalAmount);

                    } else {
                        log.error("好可惜，回调类型不存在：{}", dto.getType());
                    }

                } else {
                    log.error("支付宝APP支付，交易状态为未支付");
                    return "fail";
                }
            } catch (Exception e) {
                log.error("================支付宝回调接口处理业务代码中发生异常================");
                log.info(e.getMessage());
            }
        }
        return "success";
    }

    /**
     * 获取两个时间点的月份差
     * 
     * @param dt1
     *            第一个时间点,小的那个时间
     * @param dt2
     *            第二个时间点，大的那个时间
     * @return int，即需求的月数差
     */
    public static int monthDiff(LocalDateTime dt1, LocalDateTime dt2) {
        // 获取第一个时间点的月份
        int month1 = dt1.getMonthValue();
        // 获取第一个时间点的年份
        int year1 = dt1.getYear();
        // 获取第一个时间点的月份
        int month2 = dt2.getMonthValue();
        // 获取第一个时间点的年份
        int year2 = dt2.getYear();
        // 返回两个时间点的月数差
        return (year2 - year1) * 12 + (month2 - month1);
    }

    /**
     * 得到支付宝回调参数
     * 
     * @param request
     * @return
     */
    private Map<String, String> alipayParamsMap(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String)iter.next();
            String[] values = (String[])requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时注释掉。支付宝本身返回的就是utf-8不需要处理编码问题。
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        log.info("====支付宝回调参数====");
        log.info(params.toString());
        return params;
    }

    /**
     * 封装支付宝验签结果。
     * 
     * @param params
     *            验签字符串
     * @param alipayCertPath
     *            支付宝秘钥
     * @return
     */
    private boolean alipaySignVerifiedResult(Map<String, String> params, String alipayCertPath) {
        // 验签
        boolean signVerified = false;
        try {
            // 公钥证书验签方法。
            signVerified = AlipaySignature.rsaCertCheckV1(params, alipayCertPath, "utf-8", "RSA2");
        } catch (AlipayApiException e) {
            log.error("支付宝回调接口中，验签过程发生异常");
            log.info(e.getMessage());
        }
        return signVerified;
    }

    /**
     * 公用回传参数如果请求时传递了该参数，则返回给商户时会回传该参数。支付宝只会在同步返回（包括跳转回商户网站）和异步通知时将该参数原样返回。 本参数必须进行UrlEncode之后才可以发送给支付宝。
     *
     * @param type
     *            当前回调处理类型
     * @param memo
     *            一段描述
     * @param userId
     *            用户id
     * @param dataId
     *            操作数据id
     * @return
     * @throws UnsupportedEncodingException
     */
    private String assemblePassbackParams(Integer type, String memo, Long userId, String dataId)
        throws UnsupportedEncodingException {
        PassbackParamsDTO dto = new PassbackParamsDTO();
        dto.setType(type);
        dto.setMemo(memo);
        dto.setUserId(userId);
        dto.setDataId(dataId);
        return URLEncoder.encode(JSON.toJSONString(dto), "UTF-8");
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        Map<String, Object> map = new HashMap<>();
        map.put("type", 1);
        map.put("name", "测试");
        String strEncoder = JSON.toJSONString(map);
        String passbackParams = URLEncoder.encode(strEncoder, "UTF-8");
        System.out.println(passbackParams.length());

        passbackParams = URLDecoder.decode(passbackParams, "UTF-8");
        System.out.println(passbackParams);

        System.out.println(UUIDUtil.getUuidByTime(8));
        LocalDateTime of1 = LocalDateTime.of(2019, 9, 25, 1, 1);// 2018-9-25 01:01
        LocalDateTime of2 = LocalDateTime.of(2019, 10, 25, 23, 16); // 2019-9-25 23:16
        int month = monthDiff(of1, of2);
        System.out.println(month);
        System.out.println(LocalDateTime.now().plusMonths(10));
        if (BigDecimal.valueOf(20.00).compareTo(BigDecimal.valueOf(20.01)) == -1) {
            log.error("余额不足。");
        }

        Set<HashMap<String, Channel>> newUserChannel = new HashSet<>();
        if (!newUserChannel.isEmpty()) {

        }
    }

}
