package com.dayou.brokerage.handler;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dayou.bo.BrokerageDetailBO;
import com.dayou.bo.LeaderRatioBO;
import com.dayou.brokerage.BrokerageCalculateSupport;
import com.dayou.brokerage.MarketerBrokerageCalculator;
import com.dayou.brokerage.constants.BrokerageMode;
import com.dayou.brokerage.constants.BrokerageRule;
import com.dayou.brokerage.constants.BrokerageState;
import com.dayou.common.BaseEntity;
import com.dayou.dto.ItemDTO;
import com.dayou.entity.*;
import com.dayou.enums.GlobalConfigEnum;
import com.dayou.exception.BusinessException;
import com.dayou.service.*;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static com.dayou.brokerage.constants.BrokerageMsg.*;
import static com.dayou.brokerage.constants.BrokerageRule.LAND_MANAGER_RULE;
import static com.dayou.brokerage.constants.BrokerageRule.LAND_SUPERVISOR_RULE;
import static com.dayou.common.Constants.*;

/**
 * 类说明：土地规划部市场人员提成计算处理器
 *
 * @author: wucl
 * @since: 2023/3/6
 * created with IntelliJ IDEA.
 */
@Component
@Slf4j
public class LandMarketerBrokerageHandler extends BrokerageCalculateSupport implements MarketerBrokerageCalculator {


    @Autowired
    private LoadingCache<String,BigDecimal> marketerRatioCache;

    @Autowired
    private IUserTargetService userTargetService;

    @Autowired
    private IMarketStatService marketStatService;


    @Autowired
    private IUserService userService;
    
    @Autowired
    private IBrokeragePostRatioService brokeragePostRatioService;

    @Autowired
    private IItemBrokerageGeneralService generalService;

    @Autowired
    private ITeamMemberService teamMemberService;

    @Autowired
    private ITeamService teamService;

    @Override
    public BrokerageDetailBO predictPersonalAmount(BrokerageDetailBO bo) {
        try {
            BigDecimal ratio = bo.getRate()!=null?bo.getRate():marketerRatioCache.get(bo.mergeKey());
            bo.setRate(ratio);
            if (ratio !=null){
                checkItemBrokerageStatus(bo);
                bo.setPredictAmount(bo.getAmount().multiply(ratio.divide(HUNDRED)));
                bo.setBrokerageMode(BrokerageMode.PERSONAL.getCode());
                bo.setActualAmount(actualAmount(bo.getPredictAmount()));
                bo.setMarketerAdvanceBrokerageAble(checkMarketerPredictBrokerage(bo));
                if (checkMarketerPredictBrokerage(bo)){
                    bo.setMarketerStatus(BrokerageState.TO_PREDICTING.getCode());
                    bo.setAheadAmount(aheadAmount(bo.getPredictAmount()));
                }
            }else {
                log.info("项目id:[{}],合同金额：[{}],提成系数：[null],[未设置提成系数，无法计算客户经理提成]",bo.getId(),bo.getAmount());
            }
        }   catch (BusinessException e) {
            log.info("项目id:[{}],客户经理id：[{}],[{}]",bo.getId(),bo.getUserId(),e.getMessage());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        return bo;
    }

    @Override
    public BigDecimal aheadAmount(BigDecimal predictAmount){
        BigDecimal aheadAmount = predictAmount.multiply(MARKETER_AHEAD_SCALE);
        return aheadAmount;
    }

    @Override
    public Set<ItemBrokerageDetail> predictTeamShareAmount(BrokerageDetailBO bo, Set<LeaderRatioBO> leaderRatioBOSet) {
        Set<ItemBrokerageDetail> itemBrokerageDetails = Sets.newHashSet();
        try {
            BigDecimal ratio = bo.getRate()!=null?bo.getRate():marketerRatioCache.get(bo.mergeKey());
            if (ratio!=null){
                checkItemBrokerageStatus(bo);
                itemBrokerageDetails = leaderRatioBOSet.stream().map(x -> {
                    ItemBrokerageDetail itemBrokerageDetail = new ItemBrokerageDetail();
                    itemBrokerageDetail.setGeneralId(bo.getGeneralId());
                    itemBrokerageDetail.setUserId(x.getUserId());
                    itemBrokerageDetail.setAheadAmount(BigDecimal.ZERO);
                    itemBrokerageDetail.setAdvanceAmount(BigDecimal.ZERO);
                    itemBrokerageDetail.setActualAmount(BigDecimal.ZERO);
                    itemBrokerageDetail.setBrokerageMode(BrokerageMode.TEAM_SHARE.getCode());
                    itemBrokerageDetail.setBrokerageRule(x.getBrokerageRule());
                    BrokerageRule brokerageRuleEnum = BrokerageRule.brokerageRule(x.getBrokerageRule());
                    switch (brokerageRuleEnum){
                        case LAND_SUPERVISOR_RULE:
                            itemBrokerageDetail.setPredictAmount(supervisorAmount(bo.getAmount(),x.getUserId(),x.getRatio(),ratio));
                            break;
                        case LAND_MANAGER_RULE:
                            itemBrokerageDetail.setPredictAmount(managerAmount(bo.getAmount(),bo.getUserId(),x.getUserId(),x.getRatio()));
                            break;
                    }
                    return itemBrokerageDetail;
                }).collect(Collectors.toSet());

            }else {
                log.info("项目id:[{}],合同金额：[{}],提成系数：[null],[未设置提成系数，无法计算客户经理领导提成]",bo.getId(),bo.getAmount());
            }
        } catch (ExecutionException e) {
            log.error("获取提成缓存数据失败");
        }
        return itemBrokerageDetails;
    }

    @Override
    public BigDecimal actualTeamShareAmount(ItemBrokerageDetail itemBrokerageDetail) {
        BrokeragePostRatio postRatio = brokeragePostRatioService.getOne(new LambdaQueryWrapper<BrokeragePostRatio>()
                .eq(BrokeragePostRatio::getBrokerageRule, itemBrokerageDetail.getBrokerageRule()).eq(BaseEntity::getDeleted, Boolean.FALSE));
        if (postRatio!=null && postRatio.getBrokerageRatio()!=null){
            ItemDTO  itemDTO = generalService.getItemByBrokerageGeneralId(itemBrokerageDetail.getGeneralId());
            BrokerageRule brokerageRuleEnum = BrokerageRule.brokerageRule(itemBrokerageDetail.getBrokerageRule());
            switch (brokerageRuleEnum){
                case LAND_SUPERVISOR_RULE:
                    return supervisorAmount(itemDTO.getAmount(), itemBrokerageDetail.getUserId(),postRatio.getBrokerageRatio(), itemDTO.getRatio());
                case LAND_MANAGER_RULE:
                    return managerAmount(itemDTO.getAmount(),itemDTO.getUserId(),itemBrokerageDetail.getUserId(),postRatio.getBrokerageRatio());
            }
        }
        return BigDecimal.ZERO;
    }

    @Override
    public BrokerageDetailBO supervisorPersonalAmount(BrokerageDetailBO bo) {
        try {
            String mergeKey = bo.mergeKey();
            BigDecimal ratio = marketerRatioCache.get(mergeKey);
            bo.setRate(ratio);
            if (ratio !=null){
                checkItemBrokerageStatus(bo);
                bo.setPredictAmount(bo.getAmount().multiply(ratio.divide(HUNDRED)).multiply(SUPERVISOR_DEFAULT_BROKERAGE_SCALE));
                bo.setBrokerageMode(BrokerageMode.PERSONAL.getCode());
                bo.setActualAmount(actualAmount(bo.getPredictAmount()));
            }else {
                log.info("项目id:[{}],合同金额：[{}],提成系数：[null],[未设置提成系数，无法计算个人提成]",bo.getId(),bo.getAmount());
            }
        }   catch (BusinessException e) {
            log.info("项目id:[{}],人员id：[{}],[{}]",bo.getId(),bo.getUserId(),e.getMessage());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        return bo;
    }

    @Override
    public BigDecimal supervisorAmount(BigDecimal signAmount,Long supervisorId,BigDecimal postRatio, BigDecimal ratio) {
        //营销主管的团队提成规则 ： （合同额（团队签的）*项目类型提成系数 * 40% *0.5 ）+ [合同额（团队签的）*项目类型提成系数*40%*0.5 * 实发系数（取决于团队回款目标是否完成）]
        BigDecimal amount = signAmount
                .multiply(ratio.divide(HUNDRED))
                .multiply(postRatio.divide(HUNDRED))
                .multiply(SUPERVISOR_BROKERAGE_SCALE);

        //团队回款目标
        BigDecimal teamPaymentTarget = BigDecimal.valueOf(userTargetService.getTeamTarget(supervisorId).getPaymentTarget());
        BigDecimal teamCurrentYearPayment = marketStatService.currentYearTeamPayment(supervisorId);
        if (checkTeamMonthlyPayment(teamCurrentYearPayment, teamPaymentTarget)){
            return amount.multiply(BigDecimal.valueOf(2L));
        }
        return amount;
    }

    @Override
    public BrokerageDetailBO managerPersonalAmount(BrokerageDetailBO bo) {
        checkItemBrokerageStatus(bo);
        BigDecimal brokerageRatio = brokeragePostRatioService.getOne(new LambdaQueryWrapper<BrokeragePostRatio>()
                .eq(BrokeragePostRatio::getBrokerageRule, LAND_MANAGER_RULE.getCode()).eq(BaseEntity::getDeleted, Boolean.FALSE)).getBrokerageRatio();
        BigDecimal amount = managerAmount(bo.getAmount(), null, bo.getUserId(), brokerageRatio);
        bo.setPredictAmount(amount);
        bo.setBrokerageMode(BrokerageMode.TEAM_SHARE.getCode());
        bo.setRate(BigDecimal.ZERO);
        bo.setMarketerAdvanceBrokerageAble(Boolean.FALSE);
        bo.setBrokerageRule(LAND_MANAGER_RULE.getCode());
        return bo;
    }


    @Override
    public BrokerageVariable supervisorSettle(Long paymentId,BigDecimal paymentAmount,Long supervisorId,BigDecimal postRatio, BigDecimal ratio) {
        //营销主管的团队提成规则 ： （合同额（团队签的）*项目类型提成系数 * 40% *0.5 ）+ [合同额（团队签的）*项目类型提成系数*40%*0.5 * 实发系数（取决于团队回款目标是否完成）]
        //针对这笔回款，营销主管总提成金额
        BigDecimal brokerageAmount = paymentAmount
                .multiply(ratio.divide(HUNDRED))
                .multiply(postRatio.divide(HUNDRED));

        //固定提成部分
        BigDecimal defaultAmount = brokerageAmount.multiply(SUPERVISOR_BROKERAGE_SCALE);

        //浮动提成部分  需要判断这个团队的回款达成目标
        BigDecimal variableAmount = BigDecimal.ZERO;
        //团队回款目标
        BigDecimal teamPaymentTarget = BigDecimal.valueOf(userTargetService.getTeamTarget(supervisorId).getPaymentTarget());
        BigDecimal teamCurrentYearPayment = marketStatService.currentYearTeamPayment(supervisorId);
        if (checkTeamMonthlyPayment(teamCurrentYearPayment, teamPaymentTarget)){
            variableAmount = brokerageAmount.multiply(BigDecimal.ONE.subtract(SUPERVISOR_BROKERAGE_SCALE));
        }
        BrokerageVariable brokerageVariable = new BrokerageVariable();
        brokerageVariable.setPaymentId(paymentId);
        brokerageVariable.setUserId(supervisorId);
        brokerageVariable.setUserType(SUPERVISOR);
        brokerageVariable.setBrokerageAmount(brokerageAmount);
        brokerageVariable.setSettledAmount(defaultAmount.add(variableAmount));
        brokerageVariable.setUnsettledAmount(brokerageAmount.subtract(defaultAmount.add(variableAmount)));
        return brokerageVariable;
    }

    @Override
    public BrokerageVariable managerSettle(Long paymentId, BigDecimal paymentAmount, Long marketerId, Long managerId, BigDecimal postRatio) {
        //部门经理的团队提成规则 ：部门产值*3%+区域产值1.5%  +  （部门产值*浮动提成比例*0.2）+（部门产值*浮动提成比例*0.8*实发比例） 实发比例（取决于团队回款目标是否完成）
        //部门产值
        BigDecimal departmentAmount = paymentAmount
                .multiply(postRatio.divide(HUNDRED))
                .multiply(new BigDecimal("2"));
        BigDecimal areaAmount = BigDecimal.ZERO;

        if (marketerId!=null){
            //开单人员的营销主管集合
            Set<LeaderRatioBO> leaders = teamMemberService.getLeader(marketerId, MARKET_DEPARTMENT).stream().filter(x->x.getPostName().equals(SUPERVISOR)).collect(Collectors.toSet());

            if (!CollectionUtils.isEmpty(leaders)){
                //区域产值
                areaAmount = paymentAmount.multiply(postRatio.divide(HUNDRED));
            }
        }

        // 获取发展的营销主管个数
        int cultivateNum = teamService.count(new LambdaQueryWrapper<Team>().eq(Team::getCultivateId, managerId).eq(BaseEntity::getDeleted, Boolean.FALSE));
        BigDecimal cultivateRate ;
        if (cultivateNum<4){
            cultivateRate = CULTIVATE_LOW_4;
        }else if(cultivateNum>=4 && cultivateNum<=6){
            cultivateRate = CULTIVATE_4_6;
        }else {
            cultivateRate = CULTIVATE_HIGH_6;
        }
        BigDecimal floatAmount = paymentAmount.multiply(cultivateRate).multiply(MANAGER_FLOAT_RATIO_2);

        BigDecimal variableAmount = paymentAmount.multiply(cultivateRate).multiply(MANAGER_FLOAT_RATIO_8);

        BigDecimal brokerageAmount = departmentAmount.add(areaAmount).add(floatAmount).add(variableAmount);
        //团队回款目标
        BigDecimal teamPaymentTarget = BigDecimal.valueOf(userTargetService.getTeamTarget(managerId).getPaymentTarget());
        BigDecimal teamCurrentYearPayment = marketStatService.currentYearTeamPayment(managerId);
        if (checkTeamMonthlyPayment(teamCurrentYearPayment, teamPaymentTarget)){
            floatAmount = floatAmount.add(variableAmount);
        }
        BrokerageVariable brokerageVariable = new BrokerageVariable();
        brokerageVariable.setPaymentId(paymentId);
        brokerageVariable.setUserId(managerId);
        brokerageVariable.setUserType(MARKET_MANAGER);
        brokerageVariable.setBrokerageAmount(brokerageAmount);
        brokerageVariable.setSettledAmount(departmentAmount.add(areaAmount).add(floatAmount));
        brokerageVariable.setUnsettledAmount(brokerageAmount.subtract(brokerageVariable.getSettledAmount()));
        return brokerageVariable;
    }

    @Override
    public BigDecimal managerAmount(BigDecimal signAmount,Long marketerId, Long managerId,BigDecimal postRatio) {
        //部门经理的团队提成规则 ：部门产值*3%+区域产值1.5%  +  （部门产值*浮动提成比例*0.2）+（部门产值*浮动提成比例*0.8*实发比例） 实发比例（取决于团队回款目标是否完成）
        //部门产值
        BigDecimal departmentAmount = signAmount
                .multiply(postRatio.divide(HUNDRED))
                .multiply(new BigDecimal("2"));
        BigDecimal areaAmount = BigDecimal.ZERO;

        if (marketerId!=null){
            //开单人员的营销主管集合
            Set<LeaderRatioBO> leaders = teamMemberService.getLeader(marketerId, MARKET_DEPARTMENT).stream().filter(x->x.getPostName().equals(SUPERVISOR)).collect(Collectors.toSet());

            if (!CollectionUtils.isEmpty(leaders)){
                //区域产值
                areaAmount = signAmount.multiply(postRatio.divide(HUNDRED));
            }
        }

        // 获取发展的营销主管个数
        int cultivateNum = teamService.count(new LambdaQueryWrapper<Team>().eq(Team::getCultivateId, managerId).eq(BaseEntity::getDeleted, Boolean.FALSE));
        BigDecimal cultivateRate ;
        if (cultivateNum<4){
            cultivateRate = CULTIVATE_LOW_4;
        }else if(cultivateNum>=4 && cultivateNum<=6){
            cultivateRate = CULTIVATE_4_6;
        }else {
            cultivateRate = CULTIVATE_HIGH_6;
        }
        BigDecimal floatAmount = signAmount.multiply(cultivateRate).multiply(MANAGER_FLOAT_RATIO_2);

        //团队回款目标
        BigDecimal teamPaymentTarget = BigDecimal.valueOf(userTargetService.getTeamTarget(managerId).getPaymentTarget());
        BigDecimal teamCurrentYearPayment = marketStatService.currentYearTeamPayment(managerId);
        if (checkTeamMonthlyPayment(teamCurrentYearPayment, teamPaymentTarget)){
            floatAmount = floatAmount.add(signAmount.multiply(cultivateRate).multiply(MANAGER_FLOAT_RATIO_8));
        }
        return departmentAmount.add(areaAmount).add(floatAmount);
    }

    /**
     * 更新下单时的领导提成详情，暂不考虑领导人员变动情况
     * @param list
     * @param bo
     * @return
     */
    @Override
    public List<ItemBrokerageDetail> updateTeamShareAmount(List<ItemBrokerageDetail> list,BrokerageDetailBO bo) {

        try {
            BigDecimal ratio = bo.getRate()!=null?bo.getRate():marketerRatioCache.get(bo.mergeKey());
            if (ratio!=null){
                checkItemBrokerageStatus(bo);
                for (ItemBrokerageDetail itemBrokerageDetail : list){
                    if (itemBrokerageDetail.getGeneralId().equals(bo.getGeneralId())){
                        BrokerageRule brokerageRuleEnum = BrokerageRule.brokerageRule(itemBrokerageDetail.getBrokerageRule());
                        switch (brokerageRuleEnum){
                            case LAND_SUPERVISOR_RULE:
                                BrokeragePostRatio supervisorRatio = brokeragePostRatioService.getOne(new LambdaQueryWrapper<BrokeragePostRatio>().eq(BrokeragePostRatio::getBrokerageRule, LAND_SUPERVISOR_RULE.getCode()));
                                itemBrokerageDetail.setPredictAmount(supervisorAmount(bo.getAmount(),itemBrokerageDetail.getUserId(),supervisorRatio.getBrokerageRatio(),ratio));
                                break;
                            case LAND_MANAGER_RULE:
                                BrokeragePostRatio managerRatio = brokeragePostRatioService.getOne(new LambdaQueryWrapper<BrokeragePostRatio>().eq(BrokeragePostRatio::getBrokerageRule, LAND_MANAGER_RULE.getCode()));
                                itemBrokerageDetail.setPredictAmount(managerAmount(bo.getAmount(),bo.getUserId(),itemBrokerageDetail.getUserId(),managerRatio.getBrokerageRatio()));
                                break;
                        }
                    }
                }
            }else {
                log.info("项目id:[{}],合同金额：[{}],提成系数：[null],[未设置提成系数，无法计算客户经理领导提成]",bo.getId(),bo.getAmount());
            }
        } catch (ExecutionException e) {
            log.error("获取提成缓存数据失败");
        }
        return list;
    }

    @Override
    public BigDecimal marketerPaymentAmount(PaymentCollection paymentCollection,BigDecimal ratio) {
        return  BigDecimal.valueOf(paymentCollection.getAmount()).multiply(ratio.divide(HUNDRED));
    }

    @Override
    public BigDecimal actualAmount(BigDecimal predictAmount) {
        //客户经理的提成不存在考核，即 预计提成金额 == 实际提成金额
        return predictAmount;
    }

}
