package com.kxs.user.biz.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kxs.common.core.constant.enums.KindTypeEnum;
import com.kxs.common.core.constant.enums.UserAdvanceStatusEnum;
import com.kxs.common.core.util.R;
import com.kxs.common.core.util.SysUtils;
import com.kxs.common.mybatis.handler.MonthTableNameHandler;
import com.kxs.common.security.util.SecurityUtils;
import com.kxs.system.api.util.ParamResolver;
import com.kxs.user.api.dto.kxsapp.userAccount.PayRequestDTO;
import com.kxs.user.api.dto.kxsapp.userAccount.RefundRequestDTO;
import com.kxs.user.api.model.KxsUserAdvance;
import com.kxs.user.api.model.KxsUserAmount;
import com.kxs.user.api.model.KxsUserAmountLog;
import com.kxs.user.api.model.KxsUserYuepay;
import com.kxs.user.api.vo.kxsapp.userAccount.MyAccountVO;
import com.kxs.user.api.vo.kxsapp.userAccount.RefundResVO;
import com.kxs.user.biz.constant.enums.YuePayStatusEnum;
import com.kxs.user.biz.mapper.KxsUserAdvanceMapper;
import com.kxs.user.biz.mapper.KxsUserAmountMapper;
import com.kxs.user.biz.service.KxsUserAmountLogService;
import com.kxs.user.biz.service.KxsUserAmountService;
import com.kxs.user.biz.service.KxsUserYuepayService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * 用户账户表(KxsUserAmount)表服务实现类
 *
 * @author 系统
 * @since 2023-12-11 23:33:30
 */
@Service("kxsUserAmountService")
@RequiredArgsConstructor
public class KxsUserAmountServiceImpl extends ServiceImpl<KxsUserAmountMapper, KxsUserAmount> implements KxsUserAmountService {

    private final KxsUserAmountLogService kxsUserAmountLogService;

    private final KxsUserYuepayService kxsUserYuepayService;

    private final KxsUserAdvanceMapper kxsUserAdvanceMapper;

    @Override
    public MyAccountVO myAccount() {

        KxsUserAmount userAmount = this.getOne(Wrappers.<KxsUserAmount>lambdaQuery()
                .eq(KxsUserAmount::getUserId, SecurityUtils.getUser().getId()));

        MyAccountVO myAccountVO = new MyAccountVO();
        BeanUtils.copyProperties(userAmount, myAccountVO);

        //预扣款
        KxsUserAdvance advance = kxsUserAdvanceMapper.selectOne(Wrappers.<KxsUserAdvance>query()
                .select("IFNULL(SUM(amount), 0) as amount")
                .eq("user_id", SecurityUtils.getUser().getId())
                .eq("status", UserAdvanceStatusEnum.ADVANCE_NOT_CHARGED.getType()));
        if (advance != null) {
            //余额减去预扣款金额
            myAccountVO.setUseAmount(NumberUtil.sub(userAmount.getAmount(), advance.getAmount()));
        }

        return myAccountVO;
    }

    @Override
    public Boolean userAmountChange(KxsUserAmountLog userAmountLog) {

        KxsUserAmount userAmount = this.getOne(Wrappers.<KxsUserAmount>lambdaQuery()
                .eq(KxsUserAmount::getUserId, userAmountLog.getUserId()).last("FOR UPDATE"));

        userAmountLog.setBeforeAmount(userAmount.getAmount());
        BigDecimal afterAmount;
        //增加余额
        if (Objects.equals(userAmountLog.getKind(), KindTypeEnum.ADD.getType())) {
            afterAmount = NumberUtil.add(userAmount.getAmount(), userAmountLog.getAmount());
        } else {
            afterAmount = NumberUtil.sub(userAmount.getAmount(), userAmountLog.getAmount());
        }
        userAmountLog.setAfterAmount(afterAmount);
        userAmount.setAmount(afterAmount);

        MonthTableNameHandler.setData(MonthTableNameHandler.getThisMoth());
        kxsUserAmountLogService.save(userAmountLog);
        //删除线程，避免线程污染
        MonthTableNameHandler.removeData();

        this.updateById(userAmount);

        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R yuePay(PayRequestDTO payReq) {

        Long userId = SecurityUtils.getUser().getId();
        KxsUserAmount userAmount = this.getOne(Wrappers.<KxsUserAmount>lambdaQuery()
                .eq(KxsUserAmount::getUserId, userId));
        if (BigDecimal.valueOf(payReq.getTotalAmount()).compareTo(userAmount.getAmount()) > 0) {
            return R.failed("余额不足");
        }
        long count = kxsUserYuepayService.count(Wrappers.<KxsUserYuepay>lambdaQuery().eq(KxsUserYuepay::getOutTradeNo, payReq.getOutTradeNo()));
        if (count > 1) {
            return R.failed("该订单号已支付");
        }

        KxsUserAmountLog kxsUserAmountLog = new KxsUserAmountLog();
        kxsUserAmountLog.setAmount(BigDecimal.valueOf(payReq.getTotalAmount()));
        kxsUserAmountLog.setUserId(userId.intValue());
        //余额支付
        kxsUserAmountLog.setVariationType(ParamResolver.getInteger("RECYC_POS_MAX_DAY", 20));
        kxsUserAmountLog.setRemark("购买" + payReq.getSubject());
        kxsUserAmountLog.setKind(KindTypeEnum.SUB.getType());
        Boolean b = this.userAmountChange(kxsUserAmountLog);
        if (!b) {
            return R.failed("扣款失败");
        }
        //余额支付账单
        String tradeNo = SysUtils.generatePaymentId(userId);
        KxsUserYuepay kxsUserYuepay = new KxsUserYuepay();
        kxsUserYuepay.setSubject(payReq.getSubject());
        kxsUserYuepay.setUserId(userId);
        kxsUserYuepay.setTradeNo(tradeNo);
        kxsUserYuepay.setPassbackParams(payReq.getPassbackParams());
        kxsUserYuepay.setTradeStatus(YuePayStatusEnum.SUCCESS.getType());
        kxsUserYuepay.setOutTradeNo(payReq.getOutTradeNo());
        kxsUserYuepay.setTradeAmount(BigDecimal.valueOf(payReq.getTotalAmount()));
        kxsUserYuepayService.save(kxsUserYuepay);

        return R.ok(kxsUserYuepay);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R refund(RefundRequestDTO req) {

        KxsUserYuepay trade = kxsUserYuepayService.getOne(Wrappers.<KxsUserYuepay>lambdaQuery().eq(KxsUserYuepay::getOutTradeNo, req.getOutTradeNo()));
        if (trade == null) {
            return R.failed("订单号不存在");
        }
        if (!Objects.equals(trade.getTradeStatus(), YuePayStatusEnum.SUCCESS.getType())) {
            return R.failed("订单号已退款");
        }
        trade.setTradeStatus(YuePayStatusEnum.REFUND.getType());
        kxsUserYuepayService.updateById(trade);

        //退回到余额
        KxsUserAmount userAmount = this.getOne(Wrappers.<KxsUserAmount>lambdaQuery()
                .eq(KxsUserAmount::getUserId, trade.getUserId()));
        KxsUserAmountLog kxsUserAmountLog = new KxsUserAmountLog();
        kxsUserAmountLog.setAmount(trade.getTradeAmount());
        kxsUserAmountLog.setUserId(userAmount.getUserId());
        //余额支付
        kxsUserAmountLog.setVariationType(ParamResolver.getInteger("RECYC_POS_MAX_DAY", 519));
        kxsUserAmountLog.setRemark(req.getRefundReason());
        kxsUserAmountLog.setKind(KindTypeEnum.ADD.getType());
        Boolean b = this.userAmountChange(kxsUserAmountLog);
        if (!b) {
            return R.failed("退款失败");
        }
        return R.ok(RefundResVO.builder()
                .outTradeNo(req.getOutTradeNo())
                .passbackParams(req.getPassbackParams())
                .tradeNo(trade.getTradeNo())
                .refundFee(trade.getTradeAmount()).build());
    }


}

