package org.jeecg.modules.userCode.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.bestpay.enums.BestPayTypeEnum;
import org.jeecg.common.bestpay.model.PayRequest;
import org.jeecg.common.bestpay.model.PayResponse;
import org.jeecg.common.bestpay.service.BestPayService;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.config.shiro.ShiroRealm;
import org.jeecg.modules.bean.RechargeReq;
import org.jeecg.modules.hanHaiMember.entity.HanHaiMember;
import org.jeecg.modules.hanHaiMember.mapper.HanHaiMemberMapper;
import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService;
import org.jeecg.modules.rechargeInfoLog.entity.TbRechargeInfoLog;
import org.jeecg.modules.rechargeInfoLog.service.ITbRechargeInfoLogService;
import org.jeecg.modules.tbConf.entity.TbConf;
import org.jeecg.modules.tbConf.service.ITbConfService;
import org.jeecg.modules.tbOrder.entity.TbOrder;
import org.jeecg.modules.tbOrder.service.ITbOrderService;
import org.jeecg.modules.tbPremium.entity.TbPremium;
import org.jeecg.modules.tbPremium.service.ITbPremiumService;
import org.jeecg.modules.userCode.mapper.RechargeInfoLogMapper;
import org.jeecg.modules.userCode.model.req.OrderPayReq;
import org.jeecg.modules.userCode.model.req.PayBean;
import org.jeecg.modules.userCode.model.req.RechargeInfoLogReq;
import org.jeecg.modules.userCode.model.req.WithawalReq;
import org.jeecg.modules.userCode.service.IPayService;
import org.jeecg.modules.userRole.service.ITbUserRoleService;
import org.jeecg.modules.utils.SubmitUtil;
import org.jeecg.modules.utils.ValidateTool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author java996.icu
 * @description PayServiceImpl
 * @date 2021/4/13 15:07
 * @Version V1.0
 */
@Log4j2
@Service
public class PayServiceImpl implements IPayService {

    @Value("${wechat.notifyUrl}")
    private String httpcross;

    @Value("${wechat.notifyRechargeUrl}")
    private String httpRechargecross;
    @Value("${wechat.premiumNotifyUrl}")
    private String premiumNotifyUrl;
    @Resource
    private ShiroRealm shiroRealm;

    @Resource
    private BestPayService bestPayService;

    @Resource
    private IHanHaiMemberService hanHaiMemberService;
    @Resource
    private ITbRechargeInfoLogService rechargeInfoLogService;

    @Resource
    private RechargeInfoLogMapper rechargeInfoLogMapper;


    @Resource
    private ITbOrderService tbOrderService;

    @Resource
    private ITbPremiumService tbPremiumService;

    @Resource
    private HanHaiMemberMapper hanHaiMemberMappere;
    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ITbConfService tbConfService;

    @Resource
    private ITbRechargeInfoLogService tbRechargeInfoLogService;

    /**
     * 订单支付
     *
     * @param req
     * @param token
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> orderPay(OrderPayReq req, String token) {

        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token);
        log.warn("orderPay参数{}==={}", JSONObject.toJSONString(req));
        if (req == null) {
            throw new JeecgBootException("订单错误，请稍后重试");
        }
        if (StringUtils.isEmpty(req.getOrderId())) {
            throw new JeecgBootException("订单错误，请稍后重试");
        }

        // 查询订单信息
        TbOrder orderVO = tbOrderService.getById(req.getOrderId());
        if (ValidateTool.isNull(orderVO)) {
            return Result.error("订单记录不存在");
        }
        /**
         * 实时获取订单中的金额 (可能存在提交订单未付款,后面开通会员的情况)
         * */

        BigDecimal vipdiscount = BigDecimal.ZERO;

        BigDecimal balncePayAmount = BigDecimal.ZERO;

        BigDecimal payAmount = BigDecimal.ZERO;


        // 更新订单状态
        TbOrder cmOrder1 = new TbOrder();
        cmOrder1.setId(orderVO.getId());
        cmOrder1.setOrderStatus(8);

        tbOrderService.updateById(cmOrder1);

        // 保存订单详情


//        // 保存订单状态到redis
//        redisUtil.set(RedisKey.ORDER_INFO_PAY + cmOrder.getId(), cmOrder.getId(), 60 * 60);
        // 组装付款参数
        PayBean pay = new PayBean();
        pay.setOrderId(orderVO.getId());
        pay.setOrderName(orderVO.getTitle());
        pay.setOpenId(hanHaiMember.getAppletOpenid());
        pay.setMoney(new BigDecimal("0.01").doubleValue());
        log.warn("读取回调地址:>>>>>>{}", httpcross);
        pay.setReturnUrl(httpcross);
        PayResponse payResponse = this.create(pay);
        payResponse.setToPage(false);
        log.warn("支付数据{}", payResponse);
        return Result.OK(payResponse);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> payOrderByBalance(OrderPayReq req, String token) {

        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token);
        log.warn("orderPay参数{}==={}", JSONObject.toJSONString(req));
        if (req == null) {
            throw new JeecgBootException("订单错误，请稍后重试");
        }
        if (StringUtils.isEmpty(req.getOrderId())) {
            throw new JeecgBootException("订单错误，请稍后重试");
        }

        // 查询订单信息
        TbOrder order = tbOrderService.getById(req.getOrderId());
        if (ValidateTool.isNull(order)) {
            return Result.error("订单记录不存在");
        }
        /**
         * 实时获取订单中的金额 (可能存在提交订单未付款,后面开通会员的情况)
         * */
        if (order.getOrderStatus() == 5 || order.getOrderStatus() == 6) {
            throw new JeecgBootException("订单已支付，请勿重复支付");
        }

        if (hanHaiMember.getPrice().doubleValue() <= 0
                || hanHaiMember.getPrice().doubleValue() < order.getPayMoney().doubleValue()) {
            throw new JeecgBootException("余额不足，请充值");
        }
        UpdateWrapper<HanHaiMember> updateWrapper = new UpdateWrapper<>();
        updateWrapper.setSql("price = price - " + order.getPayMoney());
        updateWrapper.eq("id", hanHaiMember.getId()).last("and price - " + order.getPayMoney() + ">= 0");
        int update = hanHaiMemberMappere.update(null, updateWrapper);
        if (update < 1) {
            log.warn("余额扣除失败 订单id{}金额{}", order.getId(), order.getPayMoney());
            throw new JeecgBootException("网络异常");
        }
        TbRechargeInfoLog rechargeLog = new TbRechargeInfoLog();
        rechargeLog.setTitle(order.getTitle());
        rechargeLog.setMoney(order.getPayMoney());
        rechargeLog.setMemberId(hanHaiMember.getId());
        rechargeLog.setUserMoney(hanHaiMember.getPrice());
        rechargeLog.setType(0);
        rechargeLog.setIsPay(1);
        rechargeLog.setPayTime(new Date());
        rechargeLog.setOrderId(order.getId());
        rechargeInfoLogMapper.insert(rechargeLog);

        // 更新订单状态
        TbOrder cmOrder1 = new TbOrder();
        cmOrder1.setId(order.getId());
        cmOrder1.setOrderStatus(8);

        tbOrderService.updateById(cmOrder1);


        return Result.OK();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<?> notify(PayResponse payResponse) {
        try {
            log.error("进入微信付款支付回调接口>>>>>>>>>>>>>>>>>");
            if (payResponse == null) {
                return null;
            }
            TbOrder cmOrder = tbOrderService.getById(payResponse.getOrderId());
            if (cmOrder == null) {
                return null;
            }
//            if (cmOrder.getOrderStatus() > 2) {
//                return null;
//            }
            // 更新订单状态
            TbOrder cmOrder1 = new TbOrder();
            cmOrder1.setId(cmOrder.getId());
            // 待派单
            cmOrder1.setOrderStatus(5);
            // 付款时间
            cmOrder1.setPayTime(DateUtils.getDate());
            tbOrderService.updateById(cmOrder1);


            // 保存订单状态到redis
//            redisUtil.del(RedisKey.ORDER_INFO_PAY + cmOrder.getId());


            return Result.OK();
        } catch (Exception e) {
            throw new JeecgBootException("支付回调错误:" + e.getMessage());
        }


    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<?> premiumNotify(PayResponse payResponse) {
        try {
            log.error("进入保险微信付款支付回调接口>>>>>>>>>>>>>>>>>");
            if (payResponse == null) {
                return null;
            }
            TbPremium premium = tbPremiumService.getById(payResponse.getOrderId());
            if (premium == null) {
                return null;
            }

            // 更新订单状态
            TbPremium cmOrder1 = new TbPremium();
            cmOrder1.setId(premium.getId());
            // 付款时间
            cmOrder1.setPayTime(DateUtils.getDate());
            tbPremiumService.updateById(cmOrder1);
            TbOrder tbOrder = new TbOrder();
            tbOrder.setId(payResponse.getOrderId());
            tbOrder.setPremium(premium.getPremium());
            tbOrderService.updateById(tbOrder);

            return Result.OK();
        } catch (Exception e) {
            throw new JeecgBootException("支付回调错误:" + e.getMessage());
        }


    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<?> orderPremiumPay(OrderPayReq req, String token) {
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token);
        TbPremium cmOrder = tbPremiumService.getById(req.getOrderId());
        if (ValidateTool.isNotNull(cmOrder.getPremium())) {
            throw new JeecgBootException("重复支付");
        }


        TbPremium tbPremium = new TbPremium();
        tbPremium.setId(IdWorker.getIdStr());
        tbPremium.setUserId(hanHaiMember.getId());
        tbPremium.setOrderId(req.getOrderId());
        tbPremium.setMoneyType(0);
        QueryWrapper<TbConf> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("name", "premium");
        TbConf one = tbConfService.getOne(objectQueryWrapper);
        tbPremium.setPremium(new BigDecimal(one.getValue()));
        tbPremiumService.save(tbPremium);
        // 组装付款参数
        PayBean pay = new PayBean();
        pay.setOrderId(tbPremium.getId());
        pay.setOrderName(req.getOrderId() + "保险费");
        pay.setOpenId(hanHaiMember.getAppletOpenid());
        pay.setMoney(tbPremium.getPremium().doubleValue());
        log.warn("读取回调地址:>>>>>>{}", premiumNotifyUrl);
        pay.setReturnUrl(premiumNotifyUrl);
        PayResponse payResponse = this.create(pay);
        payResponse.setToPage(false);
        log.warn("支付数据{}", payResponse);
        return Result.OK(payResponse);
    }

    /**
     * 车主端-充值金额
     *
     * @param rechargeReq
     * @param token
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> payRecharge(RechargeReq rechargeReq, String token) {
        HanHaiMember cmMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token);


        TbRechargeInfoLog rechargeInfoLog = new TbRechargeInfoLog();
        rechargeInfoLog.setTitle("充值金额");
        rechargeInfoLog.setType(1);
        rechargeInfoLog.setMemberId(cmMember.getId());
        rechargeInfoLog.setMoney(rechargeReq.getPrice());
        rechargeInfoLog.setUserMoney(cmMember.getPrice());
        rechargeInfoLog.setIsPay(0);
        rechargeInfoLog.setRechargeId(null);

        boolean save = rechargeInfoLogService.save(rechargeInfoLog);
        if (!save) {
            log.error("添加充值日志出错");
            throw new JeecgBootException("系统错误，请稍后重试");
        }
        PayBean pay = new PayBean();
        pay.setOrderId(rechargeInfoLog.getId());
        pay.setOrderName(rechargeInfoLog.getTitle());
        pay.setOpenId(cmMember.getAppletOpenid());
        pay.setMoney(rechargeInfoLog.getMoney().doubleValue());
        // 设置微信回调接口地址
        pay.setReturnUrl(httpRechargecross);
        PayResponse payResponse = this.create(pay);
        return Result.OK(payResponse);
    }


    /**
     * 车主端-充值金额回调
     *
     * @param payResponse
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<?> payRechargeNotify(PayResponse payResponse) {
        try {
            log.warn("进入充值金额微信付款支付回调接口>>>>>>>>>>>>>>>>>");
            if (ValidateTool.isNull(payResponse)) {
                return null;
            }
            TbRechargeInfoLog rechargeInfoLog = rechargeInfoLogService.lambdaQuery()
                    .eq(TbRechargeInfoLog::getDelFlag, 0)
                    .eq(TbRechargeInfoLog::getIsPay, 0)
                    .eq(TbRechargeInfoLog::getId, payResponse.getOrderId()).one();
            if (rechargeInfoLog == null) {
                log.error("未找到日志订单号");
                return null;
            }
            HanHaiMember carOwner = hanHaiMemberService.getById(rechargeInfoLog.getMemberId());
            if (carOwner == null) {
                return Result.error("该用户不存在");
            }

            TbRechargeInfoLog rechargeInfoLog1 = new TbRechargeInfoLog();
            rechargeInfoLog1.setId(rechargeInfoLog.getId());
            rechargeInfoLog1.setIsPay(1);
            rechargeInfoLog1.setPayTime(new Date());
            rechargeInfoLog1.setWxCode(payResponse.getOutTradeNo());
            boolean update = rechargeInfoLogService.updateById(rechargeInfoLog1);
            if (!update) {
                log.error("支付回调----修改充值日志出错");
                throw new JeecgBootException("系统错误");
            }
            HanHaiMember cmMemberAccount1 = new HanHaiMember();
            cmMemberAccount1.setId(carOwner.getId());
            cmMemberAccount1.setPrice(carOwner.getPrice().add(rechargeInfoLog.getMoney()));
            boolean update1 = hanHaiMemberService.updateById(cmMemberAccount1);
            if (!update1) {
                log.error("支付回调----修改用户数据出错");
                throw new JeecgBootException("系统错误");
            }
        } catch (Exception e) {
            throw new JeecgBootException("支付回调错误:" + e.getMessage());
        }
        return Result.OK();
    }


    public PayResponse create(PayBean pay) {
        PayRequest payService = new PayRequest();
        payService.setOpenid(pay.getOpenId());
        payService.setOrderAmount(pay.getMoney());
        payService.setOrderId(pay.getOrderId());
        payService.setOrderName(pay.getOrderName());
        payService.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5);
        payService.setReturnUrl(pay.getReturnUrl());
        return bestPayService.pay(payService);
    }


    /**
     * 余额日志
     *
     * @return
     */
    @Transactional
    @Override
    public Result<?> rechargeLog(String token, RechargeInfoLogReq rechargeInfoLogReq) {
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token);
        LambdaQueryChainWrapper<TbRechargeInfoLog> queryChainWrapper = rechargeInfoLogService.lambdaQuery()
                .eq(TbRechargeInfoLog::getDelFlag, 0)
                .eq(TbRechargeInfoLog::getMemberId, hanHaiMember.getId())
                .eq(TbRechargeInfoLog::getIsPay, 1);

        if (ValidateTool.isNotNull(rechargeInfoLogReq.getStartTime()) && ValidateTool.isNotNull(rechargeInfoLogReq.getEndTime())) {
            queryChainWrapper.between(TbRechargeInfoLog::getCreateTime, rechargeInfoLogReq.getStartTime(), rechargeInfoLogReq.getEndTime());
        }

//        LambdaQueryChainWrapper<TbRechargeInfoLog> money = rechargeInfoLogService.lambdaQuery()
//                .eq(TbRechargeInfoLog::getMemberId, hanHaiMember.getId()).eq(TbRechargeInfoLog::getDelFlag, 0)
//                .eq(TbRechargeInfoLog::getIsPay, 1).eq(TbRechargeInfoLog::getTitle, "提现").eq(TbRechargeInfoLog::getState, 2);


        Page<TbRechargeInfoLog> page = new Page<>(rechargeInfoLogReq.getPageNo(), rechargeInfoLogReq.getPageSize());
        IPage<TbRechargeInfoLog> rechargeInfoLogList = queryChainWrapper.orderByDesc(TbRechargeInfoLog::getCreateTime).page(page);
        HashMap<String, Object> map = new HashMap<>();
        map.put("log", rechargeInfoLogList);
        map.put("money", hanHaiMember.getPrice());
        String moneyLog = rechargeInfoLogMapper.sumLog(hanHaiMember.getId());
        map.put("moneyLog", moneyLog);
        return Result.OK(map);
    }


    @Transactional
    @Override
    public Result<?> withdrawal(String token, WithawalReq withawalReq) {
        HanHaiMember account = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token);
        SubmitUtil.submit(account, "withdrawal", redisUtil);


        QueryWrapper<TbConf> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("name", "withdrawal_min_money");
        TbConf one = tbConfService.getOne(objectQueryWrapper);

        QueryWrapper<TbConf> withdrawalRate = new QueryWrapper<>();
        withdrawalRate.eq("name", "withdrawal_rate");
        TbConf withdrawalRates = tbConfService.getOne(withdrawalRate);


        //提现最低余额
        BigDecimal withawalMinMoney = new BigDecimal(one.getValue());
        if (withawalReq.getMoney().compareTo(withawalMinMoney) < 0) {
            throw new JeecgBootException("提现金额不能小于" + withawalMinMoney);
        }

        //获取提现手续费率
        BigDecimal withawalServiceRate = new BigDecimal(withdrawalRates.getValue());

        BigDecimal serviceCharge = withawalReq.getMoney().multiply(withawalServiceRate);
        BigDecimal money = withawalReq.getMoney().subtract(serviceCharge);

        if (withawalReq.getMoney().compareTo(account.getPrice()) == 1) {
            throw new JeecgBootException("提现金额不可以大于金额");
        }
        //写入提现日志
        TbRechargeInfoLog merRechargeInfoLog = new TbRechargeInfoLog();
        merRechargeInfoLog.setTitle("提现");
        merRechargeInfoLog.setMoney(money);
        merRechargeInfoLog.setUserMoney(account.getPrice());
        merRechargeInfoLog.setIsPay(1);
        merRechargeInfoLog.setPayTime(new Date());
        merRechargeInfoLog.setMemberId(account.getId());
        merRechargeInfoLog.setType(0);
        merRechargeInfoLog.setServiceCharge(serviceCharge);
        merRechargeInfoLog.setRealName(account.getName());
        merRechargeInfoLog.setState(0);
        boolean save = tbRechargeInfoLogService.save(merRechargeInfoLog);
        if (!save) {
            throw new JeecgBootException("操作失败，请稍后重试");
        }
        HanHaiMember hanHaiMember = new HanHaiMember();
        hanHaiMember.setId(account.getId());
        hanHaiMember.setPrice(account.getPrice().subtract(withawalReq.getMoney()));
        boolean b = hanHaiMemberService.updateById(hanHaiMember);
        if (!b) {
            throw new JeecgBootException("操作失败，请稍后重试");
        }
        return Result.OKMsg();
    }
}
