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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sqx.common.annotation.Debounce;
import com.sqx.common.utils.ApiAccessLimitUtil;
import com.sqx.common.utils.DateUtils;
import com.sqx.common.utils.RedisKeys;
import com.sqx.common.utils.Result;
import com.sqx.modules.app.entity.InviteAchievement;
import com.sqx.modules.app.entity.UserEntity;
import com.sqx.modules.app.entity.UserMoneyDetails;
import com.sqx.modules.app.service.InviteAchievementService;
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.job.task.TempOrdersTask;
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.context.ApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;

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

    private final OrdersService ordersService;
    private final PayDetailsDao payDetailsDao;
    private final UserMoneyService userMoneyService;
    private final UserMoneyDetailsService userMoneyDetailsService;
    private final CashOutDao cashOutDao;
    private final WuyouPay wuyouPay;
    private final TempOrdersTask ordersTask;

    WuyouController(OrdersService ordersService, PayDetailsDao payDetailsDao, CashOutDao cashOutDao, UserMoneyService userMoneyService,
                    UserMoneyDetailsService userMoneyDetailsService, TempOrdersTask ordersTask,
                    WuyouPay wuyouPay) {
        this.ordersService = ordersService;
        this.payDetailsDao = payDetailsDao;
        this.cashOutDao = cashOutDao;
        this.userMoneyService = userMoneyService;
        this.userMoneyDetailsService = userMoneyDetailsService;
        this.wuyouPay = wuyouPay;
        this.ordersTask = ordersTask;
    }

    @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(DateUtil.now());
            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) {
            ordersTask.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())) {
            payDetails.setThirdOrderNo(baseResp.getData().getOrder_sn());
            ordersTask.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 == null) {
            log.error("无忧支付回调订单不存在, 参数: {}", JSONObject.toJSONString(notifyDto));
            return "success";
        }

        if (payDetails.getState() == 1) {
            log.info("重复回调！参数: {}", JSONObject.toJSONString(notifyDto));
            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 "订单已支付";
        }

        payDetails.setThirdOrderNo(notifyDto.getOrder_sn());
        ordersTask.updateOrderStatus(payDetails, order);
        return "success";
    }


    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, cashOut.getId());
                //存入余额 钱
                userMoneyService.updateAmount(1, cashOut.getUserId(), Double.parseDouble(cashOut.getMoney()));
                userMoneyDetailsService.save(userMoneyDetails);
            }
            cashOutDao.updateById(cashOut);
        }
    }
}
