
package com.tmerclub.cloud.distribution.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.tmerclub.cloud.api.auth.vo.AuthSocialVO;
import com.tmerclub.cloud.api.platform.vo.DistributionConfigApiVO;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.DistributionAudit;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.util.PriceUtil;
import com.tmerclub.cloud.constant.DistributedIdKey;
import com.tmerclub.cloud.distribution.constant.DistributionWithdrawCashStateEnum;
import com.tmerclub.cloud.distribution.constant.EnterpriseApplyType;
import com.tmerclub.cloud.distribution.dto.AppDistributionWithdrawCashDTO;
import com.tmerclub.cloud.distribution.dto.DistributionWithdrawCashDTO;
import com.tmerclub.cloud.distribution.dto.RangeTimeDTO;
import com.tmerclub.cloud.distribution.mapper.DistributionWithdrawCashMapper;
import com.tmerclub.cloud.distribution.mapper.EnterprisePayMapper;
import com.tmerclub.cloud.distribution.model.DistributionUserWallet;
import com.tmerclub.cloud.distribution.model.DistributionUserWalletBill;
import com.tmerclub.cloud.distribution.model.DistributionWithdrawCash;
import com.tmerclub.cloud.distribution.model.EnterprisePay;
import com.tmerclub.cloud.distribution.service.*;
import com.tmerclub.cloud.distribution.service.*;
import com.tmerclub.cloud.distribution.vo.AppDistributionWithdrawCashVO;
import com.tmerclub.cloud.distribution.vo.DistributionUserVO;
import com.tmerclub.cloud.distribution.vo.DistributionWithdrawCashVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 分销员提现记录
 *
 * @author cl
 * @date 2021-08-09 14:14:10
 */
@Service
public class DistributionWithdrawCashServiceImpl implements DistributionWithdrawCashService {

    @Autowired
    private DistributionWithdrawCashMapper distributionWithdrawCashMapper;
    @Autowired
    private DistributionUserWalletService distributionUserWalletService;
    @Autowired
    private DistributionConfigService distributionConfigService;
    @Autowired
    private DistributionUserWalletBillService distributionUserWalletBillService;
    @Autowired
    private SegmentManager segmentManager;
    @Autowired
    private EnterprisePayMapper enterprisePayMapper;
    @Autowired
    private DistributionUserService distributionUserService;

    @Override
    public PageVO<DistributionWithdrawCashVO> page(PageDTO pageDTO, String userMobile, DistributionWithdrawCashDTO distributionWithdrawCashDTO) {
        return PageUtil.doPage(pageDTO, () -> distributionWithdrawCashMapper.withdrawCashPage(userMobile, distributionWithdrawCashDTO));
    }

    @Override
    public DistributionWithdrawCash getByWithdrawCashId(Long withdrawCashId) {
        return distributionWithdrawCashMapper.getByWithdrawCashId(withdrawCashId);
    }

    @Override
    public void save(DistributionWithdrawCash distributionWithdrawCash) {
        distributionWithdrawCashMapper.save(distributionWithdrawCash);
    }

    @Override
    public void update(DistributionWithdrawCash distributionWithdrawCash) {
        distributionWithdrawCashMapper.update(distributionWithdrawCash);
    }

    @Override
    public void deleteById(Long withdrawCashId) {
        distributionWithdrawCashMapper.deleteById(withdrawCashId);
    }

    @Override
    public PageVO<AppDistributionWithdrawCashVO> pageByDistributionUserId(PageDTO pageDTO, Long distributionUserId) {
        return PageUtil.doPage(pageDTO, () -> distributionWithdrawCashMapper.pageByDistributionUserId(distributionUserId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void apply(AppDistributionWithdrawCashDTO distributionWithdrawCashDTO, DistributionUserVO distributionUserVO, AuthSocialVO authSocialVO) {
        // 获取用户的钱包数据
        Long distributionUserId = distributionUserVO.getDistributionUserId();
        DistributionUserWallet distributionUserWallet = distributionUserWalletService.getByDistributionUserId(distributionUserId);
        // 获取店铺提现设置
        DistributionConfigApiVO distributionConfig = distributionConfigService.getDistributionConfig();
        BigDecimal amount = distributionWithdrawCashDTO.getAmount();

        //结算提现金额是否超出限制
        if (amount.compareTo(distributionConfig.getAmountMax()) > 0) {
            // 提现金额大于最大提现金额
            throw new LuckException("提现金额大于最大提现金额");
        }
        if (amount.compareTo(distributionConfig.getAmountMin()) < 0) {
            // 提现金额小于最小提现金额
            throw new LuckException("提现金额小于最小提现金额");
        }
        //获取店铺设置的提现频率算出时间区间
        Calendar calendar = Calendar.getInstance();
        if (Objects.equals(distributionConfig.getFrequency(), Constant.FREQUENCY_DAY)) {
            //每月的第一天
            calendar.set(Calendar.DAY_OF_MONTH, 1);
        } else {
            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - distributionConfig.getFrequency());
        }
        //将小时至0
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        //将分钟至0
        calendar.set(Calendar.MINUTE, 0);
        //将秒至0
        calendar.set(Calendar.SECOND, 0);
        //将毫秒至0
        calendar.set(Calendar.MILLISECOND, 0);
        RangeTimeDTO rangeTime = new RangeTimeDTO(calendar.getTime(), new Date());
        Integer number = distributionConfig.getNumber();
        //获取用户最近的提现次数，判断是否能够提现
        Integer count = distributionWithdrawCashMapper.getCountByRangeTimeAndDistributionUserId(rangeTime, distributionUserId);
        if (count >= number) {
            if (Objects.equals(distributionConfig.getFrequency(), Constant.FREQUENCY_DAY)) {
                // 提现次数为每月 number 次
                throw new LuckException("提现次数为每月" + number + "次");
            } else {
                // 提现次数为 天number次
                throw new LuckException("提现次数为" + distributionConfig.getFrequency() + "天" + number + "次");
            }
        }
        //判断提现金额 是否大于钱包金额
        BigDecimal settledAmount = PriceUtil.toDecimalPrice(distributionUserWallet.getSettledAmount());
        if (amount.compareTo(settledAmount) > 0) {
            // 提现失败,余额不足
            throw new LuckException("提现失败,余额不足");
        }
        //扣除可提现余额
        distributionUserWallet.setSettledAmount(PriceUtil.toLongCent(settledAmount.subtract(amount)));

        //插入一条提现记录
        Date now = new Date();
        DistributionWithdrawCash distributionWithdrawCash = new DistributionWithdrawCash();
        distributionWithdrawCash.setBizUserId(authSocialVO.getBizUserId());
        distributionWithdrawCash.setCreateTime(now);
        distributionWithdrawCash.setWalletId(distributionUserWallet.getWalletId());
        distributionWithdrawCash.setAmount(PriceUtil.toLongCent(amount));
        // 提现流水号
        Long merchantOrderId = segmentManager.getDateFormatSegmentId(DistributedIdKey.tmerclub_DISTRIBUTION_WITHDRAW_ORDER);
        distributionWithdrawCash.setMerchantOrderId(merchantOrderId.toString());
        distributionWithdrawCash.setState(DistributionWithdrawCashStateEnum.APPLY.value());
        distributionWithdrawCash.setVersion(0);
        distributionWithdrawCash.setUpdateTime(now);
        // 暂时没有手续费
        distributionWithdrawCash.setFee(Constant.ZERO_LONG);
        // 设置为手动提现
        distributionWithdrawCash.setType(0);
        // 判断人工审核后线下打款
        if (distributionConfig.getWithdrawal().equals(DistributionAudit.TWithdrawals_TWO.value())) {
            distributionWithdrawCash.setMoneyFlow(0);
        } else {
            distributionWithdrawCash.setMoneyFlow(1);
        }

        // 存入提现记录
        distributionWithdrawCashMapper.save(distributionWithdrawCash);

        // 增加钱包流水记录
        DistributionUserWalletBill distributionUserWalletBill = new DistributionUserWalletBill(distributionUserWallet, "用户提现", "User withdrawals", Constant.ZERO_LONG, -PriceUtil.toLongCent(amount), Constant.ZERO_LONG, Constant.ZERO_LONG, 0);
        distributionUserWalletBillService.save(distributionUserWalletBill);

        // 修改钱包
        DistributionUserWallet updateWallet = new DistributionUserWallet();
        updateWallet.setWalletId(distributionUserWallet.getWalletId());
        updateWallet.setSettledAmount(distributionUserWallet.getSettledAmount());
        distributionUserWalletService.update(updateWallet);

    }

    @Override
    public Integer getCountByRangeTimeAndDistributionUserId(RangeTimeDTO rangeTimeDTO, Long distributionUserId) {
        return distributionWithdrawCashMapper.getCountByRangeTimeAndDistributionUserId(rangeTimeDTO, distributionUserId);
    }

    @Override
    public Long getUserTotalWithdrawCash(Long walletId) {
        BigDecimal total = distributionWithdrawCashMapper.getUserTotalWithdrawCash(walletId);
        return total.longValue();
    }

    @Override
    public void enterprisePay(DistributionWithdrawCash distributionWithdrawCash, Long userId, String openId, Integer status) {
        // 添加商家转账记录
        EnterprisePay enterprisePay = new EnterprisePay();
        enterprisePay.setStatus(status);
        enterprisePay.setType(EnterpriseApplyType.DISTRIBUTION_WITHDRAW.value());
        enterprisePay.setBizId(distributionWithdrawCash.getWithdrawCashId());
        enterprisePay.setUserId(userId);
        enterprisePay.setOpenId(openId);
        enterprisePay.setVersion(0);
        enterprisePay.setEntPayOrderNo(new Snowflake().nextId());
        enterprisePay.setUpdateTime(new Date());
        enterprisePay.setCreateTime(new Date());
        enterprisePay.setAmount(distributionWithdrawCash.getAmount());
        enterprisePayMapper.save(enterprisePay);
    }

    @Override
    public void distributionWithdrawToSuccess(EnterprisePay enterprisePay) {
        if (!Objects.equals(enterprisePay.getType(), EnterpriseApplyType.DISTRIBUTION_WITHDRAW.value())) {
            return;
        }
        // 更新提现状态
        DistributionWithdrawCash distributionWithdrawCash = getByWithdrawCashId(enterprisePay.getBizId());
        distributionWithdrawCash.setState(DistributionWithdrawCashStateEnum.CASH_SUCCESS.value());
        distributionWithdrawCash.setUpdateTime(new Date());
        update(distributionWithdrawCash);
    }

    @Override
    public void distributionWithdrawToFailed(EnterprisePay enterprisePay) {
        //商户提现失败
        if (!Objects.equals(EnterpriseApplyType.DISTRIBUTION_WITHDRAW.value(), enterprisePay.getType())) {
            return;
        }
        DistributionWithdrawCash distributionWithdrawCash = getByWithdrawCashId(enterprisePay.getBizId());
        DistributionUserVO distributionUser = distributionUserService.getByUserId(enterprisePay.getUserId());
        DistributionUserWallet distributionUserWallet = distributionUserWalletService.getByDistributionUserId(distributionUser.getDistributionUserId());
        // 更新状态并将金额回退到分销员钱包中
        distributionWithdrawCash.setState(DistributionWithdrawCashStateEnum.CASH_FAIL.value());
        // 增加用户可提现金额
        distributionUserWallet.setSettledAmount(distributionUserWallet.getSettledAmount() + distributionWithdrawCash.getAmount());

        //增加钱包流水记录
        distributionUserWalletBillService.save(new DistributionUserWalletBill(distributionUserWallet, "提现失败", "Failed to withdraw cash", 0L, distributionWithdrawCash.getAmount(), 0L, 0L, 0));
        distributionUserWalletService.update(distributionUserWallet);
    }
}
