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

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sqx.common.annotation.Debounce;
import com.sqx.common.utils.DateUtils;
import com.sqx.common.utils.Result;
import com.sqx.modules.app.entity.UserEntity;
import com.sqx.modules.app.entity.UserMoneyDetails;
import com.sqx.modules.app.service.UserMoneyDetailsService;
import com.sqx.modules.app.service.UserMoneyService;
import com.sqx.modules.app.service.UserService;
import com.sqx.modules.common.service.CommonInfoService;
import com.sqx.modules.complet.entity.CompletAward;
import com.sqx.modules.complet.service.CompletAwardService;
import com.sqx.modules.invite.dao.InviteDao;
import com.sqx.modules.invite.entity.Invite;
import com.sqx.modules.invite.service.InviteService;
import com.sqx.modules.orders.entity.Orders;
import com.sqx.modules.orders.service.OrdersService;
import com.sqx.modules.pay.dao.CashOutDao;
import com.sqx.modules.pay.dao.PayDetailsDao;
import com.sqx.modules.pay.entity.CashOut;
import com.sqx.modules.pay.entity.PayDetails;
import com.sqx.modules.pay.wuyou.BaseResp;
import com.sqx.modules.pay.wuyou.Encrypt;
import com.sqx.modules.pay.wuyou.NotifyDto;
import com.sqx.modules.pay.wuyou.WuyouPay;
import com.sqx.modules.sys.entity.SysUserEntity;
import com.sqx.modules.sys.service.SysUserService;
import com.sqx.modules.utils.AliPayOrderUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author GYJ
 */
@Slf4j
@RestController
@Api(value = "无忧支付", tags = {"无忧支付"})
@RequestMapping("/app/wuyou")
public class WuyouController {

    private final OrdersService ordersService;
    private final PayDetailsDao payDetailsDao;
    private final UserService userService;
    private final InviteService inviteService;
    private final InviteDao inviteDao;
    private final UserMoneyService userMoneyService;
    private final UserMoneyDetailsService userMoneyDetailsService;
    private final CommonInfoService commonRepository;
    private final CashOutDao cashOutDao;
    private final CompletAwardService completAwardService;
    private final SysUserService sysUserService;
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    WuyouController(OrdersService ordersService, PayDetailsDao payDetailsDao, UserService userService, InviteService inviteService, CashOutDao cashOutDao,
                    UserMoneyService userMoneyService, UserMoneyDetailsService userMoneyDetailsService, CommonInfoService commonRepository,
                    InviteDao inviteDao,CompletAwardService completAwardService, SysUserService sysUserService) {
        this.ordersService = ordersService;
        this.payDetailsDao = payDetailsDao;
        this.userService = userService;
        this.inviteService = inviteService;
        this.cashOutDao = cashOutDao;
        this.userMoneyService = userMoneyService;
        this.userMoneyDetailsService = userMoneyDetailsService;
        this.commonRepository = commonRepository;
        this.inviteDao = inviteDao;
        this.completAwardService = completAwardService;
        this.sysUserService = sysUserService;
    }

    @Debounce(interval = 1000, value = "#orderId")
    @ApiOperation("支付订单")
    @GetMapping("/payOrder/{orderId}")
    public Result payOrder(HttpServletRequest request, @PathVariable("orderId") Long orderId, @RequestParam(value = "payType", required = false) String payType) {
        Orders order = ordersService.getById(orderId);
        if (order == null) {
            return Result.error("订单不存在");
        }

        if (order.getStatus() != 0) {
            return Result.error("订单已支付");
        }

        PayDetails payDetails = payDetailsDao.selectByOrderId(order.getOrdersNo());
        if (payDetails == null) {
            payDetails = new PayDetails();
            payDetails.setState(0);
            payDetails.setCreateTime(sdf.format(new Date()));
            payDetails.setOrderId(order.getOrdersNo());
            payDetails.setUserId(order.getUserId());
            payDetails.setMoney(order.getPayMoney().doubleValue());
            payDetails.setType(1);
            payDetails.setClassify(9);
            payDetails.setTradeNo(AliPayOrderUtil.createOrderId());
            payDetailsDao.insert(payDetails);
        } else {
            payDetails.setTradeNo(AliPayOrderUtil.createOrderId());
            payDetailsDao.updateById(payDetails);
        }

        if (order.getPayMoney().compareTo(BigDecimal.ZERO) == 0) {
            updateOrderStatus(payDetails, order);
            Map<String, Object> data = new HashMap<>();
            data.put("tradeNo", payDetails.getTradeNo());
            data.put("payStatus", 1);
            return Result.success().put("data", data);
        }

        BaseResp baseResp = WuyouPay.payOrder(payDetails.getTradeNo(), order.getPayMoney().toString(),
                request.getHeader("User-Agent"), String.format("%d-%d", order.getCourseId(), order.getCourseDetailsId()),
                payType);
        if (baseResp.getCode() == null) {
            return Result.error(baseResp.getErrorMsg());
        }
        if (baseResp.getCode() != 200) {
            return Result.error(baseResp.getMsg());
        }

        return Result.success().put("data", baseResp.getData());
    }

    @ApiOperation("查询订单支付结果")
    @GetMapping("/queryOrder/{orderId}")
    public Result queryOrder(HttpServletRequest request, @PathVariable("orderId") Long orderId) {
        Orders order = ordersService.getById(orderId);
        if (order == null) {
            return Result.error("订单不存在");
        }

        PayDetails payDetails = payDetailsDao.selectByOrderId(order.getOrdersNo());
        if (payDetails == null) {
            return Result.error("订单支付信息不存在");
        }

        if (payDetails.getState() == 1) {
            return Result.success().put("data", 1);
        }

        BaseResp baseResp = WuyouPay.queryOrder(payDetails.getTradeNo(), order.getPayMoney().toString(), request.getHeader("User-Agent"));
        if (baseResp.getCode() == null || baseResp.getCode() != 200) {
            return Result.success().put("data", 0);
        }

        if ("SUCCESS".equals(baseResp.getPayStatus())) {
            updateOrderStatus(payDetails, order);
            return Result.success().put("data", 1);
        }

        return Result.success().put("data", 0);
    }

    @PostMapping("/extractNotify")
    public String extractNotify(HttpServletRequest request, NotifyDto notifyDto) {
        CompletableFuture.runAsync(() -> {
            updateCashAsync(notifyDto);
//            try {
//                scheduledExecutorService.schedule(() -> updateCashAsync(notifyDto), 3, TimeUnit.SECONDS);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
        });
        return "success";
    }


    @PostMapping("/notify")
    public String notify(HttpServletRequest request, NotifyDto notifyDto) {
        log.info("无忧支付回调， {}", notifyDto);
        Map<String, Object> params = new HashMap<>();
        params.put("callbacks", notifyDto.getCallbacks());
        params.put("total", notifyDto.getTotal());
        params.put("out_trade_no", notifyDto.getOut_trade_no());
        params.put("pay_time", notifyDto.getPay_time());

        String sign = Encrypt.getParamsSign(params);
        if (!sign.equals(notifyDto.getSign())) {
            log.error("无忧支付回调签名错误, 参数: {}，签名结果：{}", JSONObject.toJSONString(notifyDto), sign);
//            return "签名错误";
        }

        if (!"CODE_SUCCESS".equals(notifyDto.getCallbacks())) {
            log.error("无忧支付回调 未支付成功, 参数: {}", JSONObject.toJSONString(notifyDto));
            return "success";
        }

        log.info("无忧支付回调成功, 参数: {}", JSONObject.toJSONString(notifyDto));

        PayDetails payDetails = payDetailsDao.selectByTradeNo(notifyDto.getOut_trade_no());

        if (payDetails.getState() == 1) {
            log.info("订单表信息丢失！");
            return "success";
        }

        Orders order = ordersService.selectOrderByOrdersNo(payDetails.getOrderId());
        if (order == null) {
            log.error("无忧支付回调订单不存在, 参数: {}", JSONObject.toJSONString(notifyDto));
            return "订单不存在";
        }

        if (order.getStatus() != 0) {
            log.error("无忧支付回调订单已支付, 参数: {}", JSONObject.toJSONString(notifyDto));
            return "订单已支付";
        }

        updateOrderStatus(payDetails, order);

        return "success";
    }

    public void activities(UserEntity user, UserEntity sourceUser) {
        //分享达标
        if (sourceUser != null && sourceUser.getUserId() != 1) {
            QueryWrapper<UserMoneyDetails> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("classify", 6);
            queryWrapper.eq("user_id", sourceUser.getUserId());
            queryWrapper.eq("by_user_id", user.getUserId());
            int count = userMoneyDetailsService.count(queryWrapper);
            if (count == 0) {
                //满3笔
                Integer sumOrderNum = ordersService.countOrderNum(user.getUserId(), null);
                if (sumOrderNum > Integer.parseInt(commonRepository.findOne(913).getValue())) {
                    String amount = commonRepository.findOne(912).getValue();
                    UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                    userMoneyDetails.setClassify(6);
                    userMoneyDetails.setMoney(new BigDecimal(amount));
                    userMoneyDetails.setUserId(sourceUser.getUserId());
                    userMoneyDetails.setByUserId(user.getUserId());
                    userMoneyDetails.setCreateTime(DateUtil.now());
                    userMoneyDetails.setContent("分享达标奖励" + amount + "元");
                    userMoneyDetails.setTitle("分享达标奖励");
                    userMoneyDetails.setState(2);
                    userMoneyDetails.setType(1);
                    userMoneyDetails.setMoneyType(1);
                    userMoneyDetailsService.save(userMoneyDetails);
                    //存入余额 钱
                    userMoneyService.updateAmount(1, sourceUser.getUserId(), Double.parseDouble(amount));
                    SysUserEntity sysUser = sysUserService.selectSysUserByQdCode(user.getQdCode());
                    String qdAward = commonRepository.findOne(915).getValue();

                    UserMoneyDetails userMoneyDetails4 = new UserMoneyDetails(
                            null, sysUser.getUserId(), null, "[分享达标额外奖励]", 8, 1, 2,
                            new BigDecimal(qdAward), "推广人员首次达标，额外奖励现金红包" + qdAward, 2);

                    userMoneyService.updateSysMoney(1, sysUser.getUserId(), Double.valueOf(qdAward));
                    userMoneyDetailsService.save(userMoneyDetails4);

                    Invite invite = inviteService.selectInviteByUser(sourceUser.getUserId(), user.getUserId(), 1);
                    if (invite != null) {
                        invite.setMoney(Double.valueOf(amount));
                        invite.setState(1);
                        inviteDao.updateById(invite);
                    }
                }
            }

            QueryWrapper<UserMoneyDetails> moneyDetailsQuery = new QueryWrapper<>();
            moneyDetailsQuery.eq("classify", 6);
            moneyDetailsQuery.eq("user_id", sourceUser.getUserId());
            //达标人数
            int completeCount = userMoneyDetailsService.count(moneyDetailsQuery);
            completAwardService.list(new QueryWrapper<CompletAward>().eq("invite_count", completeCount)).forEach(completAward -> {
                switch (completAward.getType()) {
                    case 1:
                        UserMoneyDetails userMoneyDetails1 = new UserMoneyDetails(
                                sourceUser.getUserId(), null, null, "[分享达标额外奖励]", 8, 1, 2,
                                completAward.getAwardNumber(), "邀请人员已有"+completAward.getInviteCount()+"人完成达标任务，额外奖励金币" + completAward.getAwardNumber(), 2);

                        userMoneyService.updateMoney(1, sourceUser.getUserId(), completAward.getAwardNumber().doubleValue());
                        userMoneyDetailsService.save(userMoneyDetails1);
                        break;
                    case 2:
                        UserMoneyDetails userMoneyDetails2 = new UserMoneyDetails(
                                sourceUser.getUserId(), null, null, "[分享达标额外奖励]", 8, 1, 2,
                                completAward.getAwardNumber(), "邀请人员已有"+completAward.getInviteCount()+"人完成达标任务，额外奖励现金红包" + completAward.getAwardNumber(), 1);

                        userMoneyService.updateAmount(1, sourceUser.getUserId(), completAward.getAwardNumber().doubleValue());
                        userMoneyDetailsService.save(userMoneyDetails2);
                        break;
                }
            });
        }
    }

    private void updateOrderStatus(PayDetails payDetails, Orders order) {
        if (payDetails.getState() == 1) {
            return;
        }

        String format = sdf.format(new Date());
        payDetailsDao.updateState(payDetails.getId(), 1, format, payDetails.getTradeNo());

        order.setPayWay(9);
        order.setStatus(1);
        order.setPayTime(DateUtils.format(new Date()));

        UserEntity user = userService.selectUserById(order.getUserId());
        UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode());
        Map<String, Object> map = inviteService.updateInvite(byUser, format, user.getUserId(), order.getPayMoney());
        Object oneUserId = map.get("oneUserId");
        if (oneUserId != null) {
            order.setOneUserId(Long.parseLong(String.valueOf(oneUserId)));
            order.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney"))));
        }
        Object twoUserId = map.get("twoUserId");
        if (twoUserId != null) {
            order.setTwoUserId(Long.parseLong(String.valueOf(twoUserId)));
            order.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney"))));
        }
        Object sysUserId = map.get("sysUserId");
        if (sysUserId != null) {
            order.setSysUserId(Long.parseLong(String.valueOf(sysUserId)));
            order.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney"))));
        }
        ordersService.updateById(order);
        ordersService.insertOrders(order);
        CompletableFuture.runAsync(() -> {
            activities(user, byUser);
        });
    }


    private void updateCashAsync(NotifyDto notifyDto){
        log.info("无忧支付提现回调， {}", notifyDto);
        Map<String, Object> params = new HashMap<>();
        params.put("callbacks", notifyDto.getCallbacks());
        params.put("total", notifyDto.getTotal());
        params.put("out_trade_no", notifyDto.getOut_trade_no());
        params.put("status", notifyDto.getStatus());
        params.put("msg", notifyDto.getMsg());

        String sign = Encrypt.getParamsSign(params);
        if (!sign.equals(notifyDto.getSign())) {
            log.error("无忧支付提现回调签名错误, 参数: {}，签名结果：{}", JSONObject.toJSONString(notifyDto), sign);
//            return "签名错误";
        }
        CashOut cashOut = cashOutDao.selectOne(new QueryWrapper<CashOut>().eq("order_number", notifyDto.getOut_trade_no()));
        if (cashOut != null) {
            if ("2".equals(notifyDto.getStatus())) {
                cashOut.setState(1);
                cashOut.setOutAt(DateUtil.now());
            } else if(!cashOut.getState().equals(2)){
                cashOut.setState(2);
                cashOut.setRefund(notifyDto.getMsg());
                if(StringUtils.isNotBlank(notifyDto.getMsg()) && notifyDto.getMsg().contains("已驳回")){
                    cashOut.setRefund("提现失败,请检查支付宝账号与收款人姓名后重试。");
                }

                UserMoneyDetails userMoneyDetails = new UserMoneyDetails(
                        cashOut.getUserId(), null, null, "提现失败", 4, 1, 1,
                        new BigDecimal(cashOut.getMoney()), "提现失败存入余额" + cashOut.getMoney() + "元", 1);
                //存入余额 钱
                userMoneyService.updateAmount(1, cashOut.getUserId(), Double.parseDouble(cashOut.getMoney()));
                userMoneyDetailsService.save(userMoneyDetails);
            }
            cashOutDao.updateById(cashOut);
        }
    }
}
