package com.sqx.modules.pay.controller.app;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sqx.common.utils.DateUtils;
import com.sqx.common.utils.Result;
import com.sqx.modules.app.annotation.Login;
import com.sqx.modules.app.dao.UserDao;
import com.sqx.modules.app.dao.UserMoneyDao;
import com.sqx.modules.app.entity.UserEntity;
import com.sqx.modules.app.entity.UserMoney;
import com.sqx.modules.app.entity.UserMoneyDetails;
import com.sqx.modules.app.entity.VipDetails;
import com.sqx.modules.app.service.UserMoneyDetailsService;
import com.sqx.modules.app.service.UserMoneyService;
import com.sqx.modules.app.service.UserVipService;
import com.sqx.modules.app.service.VipDetailsService;
import com.sqx.modules.common.entity.CommonInfo;
import com.sqx.modules.common.service.CommonInfoService;
import com.sqx.modules.orders.entity.Orders;
import com.sqx.modules.orders.service.OrdersService;
import com.sqx.modules.pay.config.AliPayConstants;
import com.sqx.modules.pay.dao.PayDetailsDao;
import com.sqx.modules.pay.entity.PayDetails;
import com.sqx.modules.rechargeConfig.entity.RechargeConfig;
import com.sqx.modules.rechargeConfig.service.RechargeConfigService;
import com.sqx.modules.tbCoupon.entity.TbCoupon;
import com.sqx.modules.tbCoupon.service.TbCouponService;
import com.sqx.modules.tbCoupon.service.TbCouponUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 支付宝支付处理--暂不做同步处理、回调方式使用异步
 */
@Slf4j
@RestController
@Api(value = "支付宝支付", tags = {"支付宝支付"})
@RequestMapping("/app/aliPay")
public class AliPayController {

    @Autowired
    private CommonInfoService commonInfoService;
    @Autowired
    private UserMoneyDao userMoneyDao;
    @Autowired
    private PayDetailsDao payDetailsDao;
    @Autowired
    private UserMoneyDetailsService userMoneyDetailsService;
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserMoneyService userMoneyService;
    @Autowired
    private TbCouponService couponService;
    @Autowired
    private TbCouponUserService couponUserService;
    @Autowired
    private RechargeConfigService configService;
    @Autowired
    private OrdersService ordersService;
    @Autowired
    private VipDetailsService vipDetailsService;
    @Autowired
    private UserVipService userVipService;
    private ExecutorService newCachedThreadPool = new ThreadPoolExecutor(30, 100, 0L,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(1024),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    @RequestMapping(value = "/notifyApp", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    public void notifyApp(HttpServletRequest request, HttpServletResponse response) {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator 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] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        try {
            log.info("回调成功！！！");
            boolean flag = AlipaySignature.rsaCheckV1(params, commonInfoService.findOne(64).getValue(), AliPayConstants.CHARSET, "RSA2");
            log.info(flag + "回调验证信息");
            if (flag) {
                String tradeStatus = params.get("trade_status");
                if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {

                    //支付宝返回的订单编号
                    String outTradeNo = params.get("out_trade_no");
                    log.error(outTradeNo);
                    //支付宝支付单号
                    String tradeNo = params.get("trade_no");
                    PayDetails payDetails = payDetailsDao.selectByOrderId(outTradeNo);
                    if (payDetails.getState() == 0) {
                        payDetails.setState(1);
                        payDetails.setPayTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                        payDetails.setTradeNo(tradeNo);
                        payDetailsDao.updateById(payDetails);
                        if (payDetails.getType() == 1) {
                            //充值金额
                            payDetails.setClassify(4);
                            payDetailsDao.updateById(payDetails);
                            //修改用户钱包余额
                            int count = userMoneyDao.selectCount(new QueryWrapper<UserMoney>().eq("user_id", payDetails.getUserId()));
                            //如果用户钱包不存在
                            if (count == 0) {
                                UserMoney userMoney = new UserMoney();
                                userMoney.setMoney(BigDecimal.ZERO);
                                userMoney.setUserId(payDetails.getUserId());
                                userMoneyDao.insert(userMoney);
                            }
                            userMoneyService.updateMoney(1, payDetails.getUserId(), payDetails.getMoney());
                            UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                            userMoneyDetails.setMoney(BigDecimal.valueOf(payDetails.getMoney()));
                            userMoneyDetails.setUserId(payDetails.getUserId());
                            userMoneyDetails.setTitle("充值金额");
                            userMoneyDetails.setUserType(1);
                            userMoneyDetails.setContent("支付宝充值金额：" + payDetails.getMoney());
                            userMoneyDetails.setClassify(4);
                            userMoneyDetails.setType(1);
                            userMoneyDetails.setCreateTime(new SimpleDateFormat("yyyy-MM-dd :HH:mm:ss").format(new Date()));
                            userMoneyDetailsService.save(userMoneyDetails);
                            RechargeConfig rechargeConfig = configService.getById(payDetails.getParentId());
                            if (rechargeConfig!=null){
                                TbCoupon tbCoupon = couponService.getById(rechargeConfig.getCouponId());
                                if (tbCoupon != null) {
                                    for (int i = 0; i < rechargeConfig.getCouponNum(); i++) {
                                        couponUserService.giveCoupon(tbCoupon, payDetails.getUserId());
                                    }
                                }
                            }
                        } else if(payDetails.getType() == 2){
                            Orders orders = ordersService.getById(Long.parseLong(payDetails.getParentId()));
                            UserMoneyDetails userMoneyDetails=new UserMoneyDetails();
                            userMoneyDetails.setTitle("支付订单："+orders.getOrdersNo());
                            userMoneyDetails.setContent("支付宝支付："+orders.getPayMoney());
                            userMoneyDetails.setUserType(1);
                            userMoneyDetails.setUserId(orders.getUserId());
                            userMoneyDetails.setMoney(orders.getPayMoney());
                            userMoneyDetails.setType(2);
                            userMoneyDetails.setClassify(7);
                            userMoneyDetails.setCreateTime(DateUtils.format(new Date()));
                            userMoneyDetailsService.save(userMoneyDetails);
                            orders.setStatus(2);
                            orders.setPayWay(payDetails.getClassify());
                            orders.setPayTime(DateUtils.format(new Date()));
                            ordersService.updateById(orders);
                            newCachedThreadPool.submit(() -> {
                                ordersService.sendOrdersMessage(orders);
                            });
                        }else if(payDetails.getType()==3){
                            userVipService.setMember(Long.parseLong(payDetails.getParentId()),payDetails.getUserId());
                        }else if (payDetails.getType() == 4) {
                            //将保证金添加到师傅保证金里
                            Double cashDeposit = payDetails.getMoney();
                            Long userId = payDetails.getUserId();
                            userDao.updateCashDeposit(userId, cashDeposit);
                            //交保证金的记录
                            UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                            userMoneyDetails.setUserId(userId);
                            userMoneyDetails.setUserType(2);
                            userMoneyDetails.setTitle("缴纳保证金");
                            userMoneyDetails.setContent("缴纳保证金：" + cashDeposit + "元");
                            userMoneyDetails.setType(1);
                            userMoneyDetails.setClassify(1);
                            userMoneyDetails.setMoney(BigDecimal.valueOf(cashDeposit));
                            userMoneyDetails.setCreateTime(new SimpleDateFormat("yyyy-MM-dd :HH:mm:ss").format(new Date()));
                            userMoneyDetailsService.save(userMoneyDetails);
                        }
                    }
                }

            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info("回调验证失败！！！");
        }
    }

    @Login
    @ApiOperation("支付宝支付订单")
    @PostMapping("/payOrders")
    public Result payOrders(@RequestAttribute("userId") Long userId,Long ordersId,Integer type) throws Exception {
        CommonInfo one = commonInfoService.findOne(19);
        String returnUrl = one.getValue() + "/my/wallet/index";
        CommonInfo one3 = commonInfoService.findOne(12);
        String name = one3.getValue();
        String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp";
        log.info("回调地址:" + url);
        String generalOrder = getGeneralOrder();
        Orders orders = ordersService.getById(ordersId);

        PayDetails payDetails = new PayDetails();
        payDetails.setState(0);
        payDetails.setCreateTime(sdf.format(new Date()));
        payDetails.setOrderId(generalOrder);
        payDetails.setUserId(userId);

        payDetails.setParentId(ordersId.toString());
        payDetails.setMoney(orders.getPayMoney().doubleValue());
        payDetails.setClassify(4);
        payDetails.setType(2);
        payDetailsDao.insert(payDetails);
        if(type==1){
            return payH5(generalOrder, name, orders.getPayMoney(), url, returnUrl);
        }else{
            return payApp(generalOrder, name, orders.getPayMoney(), url);
        }
    }

    @Login
    @ApiOperation("支付宝开通会员")
    @PostMapping("/payMember")
    public Result payMember(Long vipId,@RequestAttribute("userId") Long userId, Integer type) throws Exception {
        CommonInfo one = commonInfoService.findOne(19);
        String returnUrl = one.getValue() + "/my/wallet/index";
        CommonInfo one3 = commonInfoService.findOne(12);
        String name = one3.getValue();
        String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp";
        log.info("回调地址:" + url);
        String generalOrder = getGeneralOrder();
        VipDetails vipDetails = vipDetailsService.getById(vipId);

        PayDetails payDetails = new PayDetails();
        payDetails.setState(0);
        payDetails.setCreateTime(sdf.format(new Date()));
        payDetails.setOrderId(generalOrder);
        payDetails.setUserId(userId);

        payDetails.setParentId(vipId.toString());
        payDetails.setMoney(vipDetails.getMoney().doubleValue());
        payDetails.setClassify(4);
        payDetails.setType(3);
        payDetailsDao.insert(payDetails);
        if(type==1){
            return payH5(generalOrder, name, vipDetails.getMoney(), url, returnUrl);
        }else{
            return payApp(generalOrder, name, vipDetails.getMoney(), url);
        }
    }


    @Login
    @ApiOperation("支付宝h5充值金额")
    @RequestMapping(value = "/payH5Money", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    public Result payH5Money(@RequestAttribute("userId") Long userId, BigDecimal money, Long rechargeId) {

        CommonInfo one = commonInfoService.findOne(19);
        String returnUrl = one.getValue() + "/my/wallet/index";
        CommonInfo one3 = commonInfoService.findOne(12);
        String name = one3.getValue();
        String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp";
        log.info("回调地址:" + url);
        String generalOrder = getGeneralOrder();
        PayDetails payDetails = new PayDetails();
        payDetails.setState(0);
        payDetails.setCreateTime(sdf.format(new Date()));
        payDetails.setOrderId(generalOrder);
        payDetails.setUserId(userId);

        //通知页面地址
        RechargeConfig rechargeConfig = configService.getById(rechargeId);
        if (rechargeConfig != null) {
            money = rechargeConfig.getMoney();
            payDetails.setParentId(rechargeId.toString());
        }
        payDetails.setMoney(money.doubleValue());
        payDetails.setClassify(4);
        payDetails.setType(1);
        payDetailsDao.insert(payDetails);
        return payH5(generalOrder, name, money, url, returnUrl);
    }

    public Result payH5(String generalOrder, String name, BigDecimal money, String url, String returnUrl) {
        try {
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonInfoService.findOne(63).getValue(), commonInfoService.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonInfoService.findOne(64).getValue(), "RSA2");
            AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
            JSONObject order = new JSONObject();
            order.put("out_trade_no", generalOrder); //订单号
            order.put("subject", name); //商品标题
            order.put("product_code", "QUICK_WAP_WAY");
            order.put("body", name);//商品名称
            order.put("total_amount", money); //金额
            alipayRequest.setBizContent(order.toString());
            //在公共参数中设置回跳和通知地址
            alipayRequest.setNotifyUrl(url);
            //通知页面地址
            alipayRequest.setReturnUrl(returnUrl);
            String form = alipayClient.pageExecute(alipayRequest).getBody();
            return Result.success().put("data", form);
        } catch (AlipayApiException e) {
            log.error("CreatPayOrderForH5", e);
        }
        return Result.error("获取订单信息错误！");
    }


    @Login
    @ApiOperation("充值金额")
    @RequestMapping(value = "/payAppMoney", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    public Result payAppMoney(@RequestAttribute("userId") Long userId, BigDecimal money, Long rechargeId) {
        CommonInfo one = commonInfoService.findOne(19);
        CommonInfo one3 = commonInfoService.findOne(12);

        String name = one3 == null ? "代驾" : one3.getValue();
        String generalOrder = getGeneralOrder();
        String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp";
        PayDetails payDetails = new PayDetails();
        payDetails.setState(0);
        payDetails.setCreateTime(sdf.format(new Date()));
        payDetails.setOrderId(generalOrder);
        payDetails.setUserId(userId);
        //通知页面地址
        RechargeConfig rechargeConfig = configService.getById(rechargeId);
        if (rechargeConfig != null) {
            money = rechargeConfig.getMoney();
            payDetails.setParentId(rechargeId.toString());
        }
        payDetails.setMoney(money.doubleValue());
        payDetails.setClassify(4);
        payDetails.setType(1);
        payDetailsDao.insert(payDetails);
        return payApp(generalOrder, name, money, url);
    }

    public Result payApp(String generalOrder, String name, BigDecimal money, String url) {
        try {
            //实例化客户端
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonInfoService.findOne(63).getValue(), commonInfoService.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonInfoService.findOne(64).getValue(), "RSA2");
            //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
            //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody(name);
            model.setSubject(name);
            model.setOutTradeNo(generalOrder);
            model.setTimeoutExpress("30m");
            model.setTotalAmount(String.valueOf(money));
            model.setProductCode("QUICK_MSECURITY_PAY");
            request.setBizModel(model);
            request.setNotifyUrl(url);
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            if (response.isSuccess()) {
                return Result.success().put("data", response.getBody());
            } else {
                return Result.error("获取订单失败！");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return Result.error(-100, "获取订单失败！");
    }



    @Login
    @ApiOperation("支付宝师傅补交保证金")
    @RequestMapping(value = "/aliPayRiderCashDeposit", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    public Result aliPayRiderCashDeposit(@RequestAttribute("userId") Long userId, Double cashDeposit,Integer classify) {
        CommonInfo one = commonInfoService.findOne(19);
        CommonInfo one3 = commonInfoService.findOne(12);
        CommonInfo one1 = commonInfoService.findOne(261);
        String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp";
        String name = one3 == null ? "代驾" : one3.getValue();
        String returnUrl = one.getValue() + "/pages/task/recharge";
        String generalOrder = getGeneralOrder();
        PayDetails payDetails = new PayDetails();
        payDetails.setState(0);
        payDetails.setCreateTime(sdf.format(new Date()));
        payDetails.setOrderId(generalOrder);
        payDetails.setUserId(userId);
        payDetails.setMoney(cashDeposit);
        payDetails.setClassify(classify);
        payDetails.setType(4);
        payDetailsDao.insert(payDetails);
        if (classify == 4) {
            return payApp(generalOrder, name, new BigDecimal(one1.getValue()), url);
        }
        return payH5(generalOrder, name, new BigDecimal(one1.getValue()), url, returnUrl);
    }


    public String getGeneralOrder() {
        Date date = new Date();
        String newString = String.format("%0" + 4 + "d", (int) ((Math.random() * 9 + 1) * 1000));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String format = sdf.format(date);
        return format + newString;
    }


    /**
     * 说明： 支付宝订单退款
     *
     * @return 公共返回参数 code,msg,   响应参数实例: https://docs.open.alipay.com/api_1/alipay.trade.refund
     */
    public boolean aliRefund(PayDetails payDetails) {
        try {
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonInfoService.findOne(63).getValue(), commonInfoService.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonInfoService.findOne(64).getValue(), "RSA2");
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(payDetails.getOrderId()); //订单号
            model.setRefundAmount(payDetails.getMoney() + ""); //退款金额
            model.setOutRequestNo(payDetails.getTradeNo()); //退款单号
            request.setBizModel(model);
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                return true;
            } else {
                return false;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("支付宝退款失败！，订单号" + payDetails.getOrderId() + "，失败原因：" + e.getMessage(), e);
        }
        return false;
    }


}
