package com.hfkj.service.rebate.impl;

import com.hfkj.common.exception.BaseException;
import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.utils.DateUtil;
import com.hfkj.dao.BsRebateRewardMapper;
import com.hfkj.entity.*;
import com.hfkj.service.BsMerService;
import com.hfkj.service.rebate.BsRebateConfigService;
import com.hfkj.service.rebate.BsRebateMerAccountService;
import com.hfkj.service.rebate.BsRebateRewardRosterService;
import com.hfkj.service.rebate.BsRebateRewardService;
import com.hfkj.service.rebate.model.RebateMerAccountTradeObject;
import com.hfkj.sysenum.RebateConfigTypeEnum;
import com.hfkj.sysenum.RebateMerAccountObjectTypeEnum;
import com.hfkj.sysenum.RebateRewardRosterStatusEnum;
import com.hfkj.sysenum.RebateRewardStatusEnum;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @className: BsRebateRewardServiceImpl
 * @author: HuRui
 * @date: 2023/10/10
 **/
@Service("rebateRewardService")
public class BsRebateRewardServiceImpl implements BsRebateRewardService {

    @Resource
    private BsRebateRewardMapper rebateRewardMapper;
    @Resource
    private BsRebateConfigService rebateConfigService;
    @Resource
    private BsRebateMerAccountService rebateMerAccountService;
    @Resource
    private BsRebateRewardRosterService rebateRewardRosterService;
    @Resource
    private BsMerService merService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void editData(BsRebateReward rebateReward) {
        if (rebateReward.getId() == null) {
            rebateReward.setCreateTime(new Date());
            rebateReward.setUpdateTime(new Date());
            rebateRewardMapper.insert(rebateReward);
        } else {
            rebateReward.setUpdateTime(new Date());
            rebateRewardMapper.updateByPrimaryKey(rebateReward);
        }
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW,rollbackFor= {RuntimeException.class})
    public void createReward(Date timeStart, Date timeEnd, List<Long> merIdList) {
        // 返利金比例
        BsRebateConfig ratio = rebateConfigService.getConfig(RebateConfigTypeEnum.type1);
        if (ratio == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的返利金比例");
        }
        String timeStartStr = DateUtil.date2String(timeStart, DateUtil.Y_M_D_HMS);
        String timeEndStr = DateUtil.date2String(timeEnd, DateUtil.Y_M_D_HMS);

        BsRebateReward rebateReward = new BsRebateReward();
        rebateReward.setBatchIdentifier(Long.parseLong(DateUtil.date2String(new Date(), "yyyyMMddHHmm")));
        rebateReward.setTimeStart(timeStart);
        rebateReward.setTimeEnd(timeEnd);
        rebateReward.setPartTradeAmount(rebateRewardMapper.queryTradeAmount(timeStartStr,timeEndStr));
        rebateReward.setPartMerNum(merIdList.size());
        rebateReward.setRatio(new BigDecimal(ratio.getParam()));
        rebateReward.setAmount(rebateReward.getPartTradeAmount().multiply(rebateReward.getRatio().divide(new BigDecimal("100"))).setScale(2, RoundingMode.DOWN));
        rebateReward.setStatus(RebateRewardStatusEnum.status1.getNumber());
        editData(rebateReward);

        // 商户返利金占比
        List<Map<String, Object>> merRatioList = rebateRewardMapper.queryTradeRatio(timeStartStr, timeEndStr, StringUtils.join(merIdList, ","));

        // 返利名单
        BsRebateRewardRoster roster;
        for (Long merId : merIdList) {
            // 查询商户
            BsMer mer = merService.getMer(merId);
            if (mer == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的商户"+merId);
            }
            roster = new BsRebateRewardRoster();
            roster.setBatchIdentifier(rebateReward.getBatchIdentifier());
            roster.setSalesmanId(mer.getSalesmanId());
            roster.setSalesmanName(mer.getSalesmanName());
            roster.setMerId(mer.getId());
            roster.setMerNo(mer.getMerNo());
            roster.setMerName(mer.getMerName());
            roster.setMerAbbreviate(mer.getMerAbbreviate());
            roster.setMerAccountNumber(rebateMerAccountService.getAccountByMerId(merId).getAccountNumber());
            List<Map<String, Object>> collect = merRatioList.stream().filter(o -> o.get("merId").equals(merId)).collect(Collectors.toList());
            if (!collect.isEmpty()) {
                roster.setRewardRatio(new BigDecimal(MapUtils.getString(collect.get(0), "ratio")));
            } else {
                roster.setRewardRatio(new BigDecimal("0"));
            }
            roster.setAmount(rebateReward.getAmount().multiply(roster.getRewardRatio().divide(new BigDecimal("100"))).setScale(2, RoundingMode.DOWN));
            roster.setStatus(RebateRewardRosterStatusEnum.status1.getNumber());
            rebateRewardRosterService.editDate(roster);
        }
    }

    @Override
    public void grantReward(Long batchIdentifier) {
        try {
            // 占坑
            Boolean lock = redisTemplate.opsForValue().setIfAbsent("GRANT_REWARD_" + batchIdentifier, null);
            if(lock) {
                // 查询奖池
                BsRebateReward rebateReward = getRebateReward(batchIdentifier);
                if (rebateReward == null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的奖池");
                }
                if (!rebateReward.getStatus().equals(RebateRewardStatusEnum.status1.getNumber())) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "奖池状态无法发放");
                }
                List<BsRebateRewardRoster> rosterList = rebateRewardRosterService.getRosterList(batchIdentifier);
                for (BsRebateRewardRoster roster : rosterList) {
                    // 资金发放商户
                    RebateMerAccountTradeObject accountTradeObject = new RebateMerAccountTradeObject();
                    accountTradeObject.setTradeObjectType(RebateMerAccountObjectTypeEnum.type2);
                    accountTradeObject.setTradeObjectId(rebateReward.getId());
                    rebateMerAccountService.income(roster.getMerAccountNumber(), roster.getAmount(), accountTradeObject);

                    roster.setStatus(RebateRewardRosterStatusEnum.status2.getNumber());
                    rebateRewardRosterService.editDate(roster);
                }

                rebateReward.setStatus(RebateRewardStatusEnum.status2.getNumber());
                editData(rebateReward);
            } else {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "请勿频繁提交，任务正在进行中...");
            }
        } catch (BaseException e) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, e.getErrorMsg());

        } catch (Exception e) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "任务出现未知错误");

        } finally {
            redisTemplate.delete("GRANT_REWARD_" + batchIdentifier);

        }
    }

    @Override
    public BsRebateReward getRebateReward(Long batchIdentifier) {
        BsRebateRewardExample example = new BsRebateRewardExample();
        example.createCriteria().andBatchIdentifierEqualTo(batchIdentifier);
        List<BsRebateReward> list = rebateRewardMapper.selectByExample(example);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public List<BsRebateReward> getRebateRewardList(Map<String, Object> param) {
        BsRebateRewardExample example = new BsRebateRewardExample();
        BsRebateRewardExample.Criteria criteria = example.createCriteria()
                                                  .andStatusNotEqualTo(RebateRewardStatusEnum.status0.getNumber());

        if (MapUtils.getLong(param, "batchIdentifier") != null) {
            criteria.andBatchIdentifierEqualTo(MapUtils.getLong(param, "batchIdentifier"));
        }

        if (MapUtils.getInteger(param, "status") != null) {
            criteria.andStatusEqualTo(MapUtils.getInteger(param, "status"));
        }

        example.setOrderByClause("create_time desc");
        return rebateRewardMapper.selectByExample(example);
    }
}
