package com.dayou.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dayou.brokerage.MarketerBrokerageCalculator;
import com.dayou.brokerage.constants.BrokerageBusiness;
import com.dayou.brokerage.constants.BrokerageMode;
import com.dayou.brokerage.constants.BrokerageRule;
import com.dayou.brokerage.constants.BrokerageState;
import com.dayou.brokerage.handler.LandMarketerBrokerageHandler;
import com.dayou.common.BaseEntity;
import com.dayou.dto.DeductionDTO;
import com.dayou.dto.ItemDTO;
import com.dayou.dto.PaymentDetailDTO;
import com.dayou.entity.*;
import com.dayou.enums.LandTechDepartmentEnum;
import com.dayou.mapper.*;
import com.dayou.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dayou.utils.DateUtils;
import com.dayou.vo.BrokerageSequenceVO;
import com.dayou.vo.IdNameVO;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 项目提成流水 服务实现类
 * </p>
 *
 * @author wucl
 * @since 2023-03-03
 */
@Slf4j
@Service
public class ItemBrokerageSequenceServiceImpl extends ServiceImpl<ItemBrokerageSequenceMapper, ItemBrokerageSequence> implements IItemBrokerageSequenceService {

    @Autowired
    private IItemBrokerageSequenceDetailService brokerageSequenceDetailService;

    @Autowired
    private IItemBrokerageGeneralService brokerageGeneralService;

    @Autowired
    private IItemBrokerageDetailService brokerageDetailService;

    @Autowired
    private LoadingCache<Long,BigDecimal> baseAmountsCache;

    @Autowired
    private ItemBrokerageSequenceMapper brokerageSequenceMapper;

    @Autowired
    private MarketerBrokerageCalculator landMarketerBrokerageHandler;

    @Autowired
    private LandMarketerBrokerageHandler marketerBrokerageHandler;

    @Autowired
    private IBrokerageVariableService brokerageVariableService;

    @Autowired
    private IBrokeragePostRatioService brokeragePostRatioService;

    @Autowired
    private IUserTargetService userTargetService;

    @Autowired
    private IMarketStatService marketStatService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IItemBrokerageTechnicistService technicistService;

    @Autowired
    private ItemBrokerageTechnicistMapper technicistMapper;

    @Autowired
    private IItemBrokerageTechnicistDeductionService deductionService;

    @Autowired
    private ItemBrokerageTechnicistDeductionMapper deductionMapper;

    @Autowired
    private BrokerageMarketerSettledMapper brokerageMarketerSettledMapper;

    @Autowired
    private IBrokerageMarketerSettledService brokerageMarketerSettledService;

    @Autowired
    private IItemBrokerageSequenceService itemBrokerageSequenceService;

    @Override
    @SuppressWarnings("unchecked")
    public Page<BrokerageSequenceVO> selectPage(Page page, BrokerageSequenceVO itemBrokerageSequence){
        Page<BrokerageSequenceVO> xPage = brokerageSequenceMapper.getPage(page,itemBrokerageSequence);
        return xPage;
    }


    @Override
    public ItemBrokerageSequence detail(Long id){
        return this.getById(id);
    }

    @Override
    public Boolean add(ItemBrokerageSequence itemBrokerageSequence){
        return  this.save(itemBrokerageSequence);
    }

    @Override
    public Boolean update(ItemBrokerageSequence itemBrokerageSequence){
        return  this.updateById(itemBrokerageSequence);
    }

    @Override
    public Boolean delete(Long id){
        //逻辑删除
        return this.removeById(id);
    }

    /**
     * 非市场人员固定预提结算
     * @return
     */
    @Transactional
    @Override
    public Set<Long> doNonMarketerAheadSettle() {
        ConcurrentMap<Long, BigDecimal> nonMarketerAheadAmounts = baseAmountsCache.asMap();
        log.info("技术人员默认预提的人数",nonMarketerAheadAmounts.size());
        Date now = new Date();
        int year = DateUtils.getYear(now);
        int month = DateUtils.getMonth(now);
        for (Map.Entry<Long,BigDecimal> nonMarketerAheadAmount : nonMarketerAheadAmounts.entrySet()){
            Long userId = nonMarketerAheadAmount.getKey();
            BigDecimal defaultAmount = nonMarketerAheadAmount.getValue();
            ItemBrokerageSequence defaultSequence = ItemBrokerageSequence.builder()
                    .brokerageAmount(defaultAmount)
                    .userId(userId)
                    .cate(BrokerageBusiness.DEFAULT_AHEAD.getCode())
                    .embody(BROKERAGE_SEQUENCE_EMBODY.replace(YEARMONTH,year+"-"+month))
                    .remark(NON_MARKETER_BASE_SEQUENCE_REMARK)
                    .year(year)
                    .month(month)
                    .build();
            this.save(defaultSequence);
            //若有全额回款的项目一次性结算提成
            List<ItemBrokerageTechnicist> brokerages = technicistMapper.notSettleForTechnicist(userId);
            if (CollectionUtils.isNotEmpty(brokerages)){
                for (ItemBrokerageTechnicist brokerage : brokerages){
                    if (brokerage!=null && brokerage.getResidueAmount()!=null){
                        ItemBrokerageSequence itemSequence = ItemBrokerageSequence.builder()
                                .brokerageAmount(brokerage.getResidueAmount())
                                .userId(userId)
                                .cate(BrokerageBusiness.ONCE_SETTLE.getCode())
                                .embody(BROKERAGE_SEQUENCE_EMBODY.replace(YEARMONTH,year+"-"+month))
                                .remark(NON_MARKETER_ALL_PAYMENT_REMARK)
                                .year(year)
                                .month(month)
                                .build();
                        technicistService.update(new LambdaUpdateWrapper<ItemBrokerageTechnicist>().set(ItemBrokerageTechnicist::getResidueAmount,BigDecimal.ZERO).eq(BaseEntity::getId,brokerage.getId()));
                        this.save(itemSequence);
                        ItemBrokerageTechnicistDeduction deduction = ItemBrokerageTechnicistDeduction.builder()
                                .brokerageTechnicistId(brokerage.getId()).brokerageSequenceId(itemSequence.getId()).deductionAmount(itemSequence.getBrokerageAmount()).build();
                        deductionService.save(deduction);
                    }
                }
            }

            //抵扣逻辑
            //可抵扣的项目
            List<ItemBrokerageTechnicist> deductionAble = technicistService.list(new LambdaQueryWrapper<ItemBrokerageTechnicist>()
                    .eq(ItemBrokerageTechnicist::getUserId, userId).ne(ItemBrokerageTechnicist::getResidueAmount, BigDecimal.ZERO).orderByAsc(BaseEntity::getId));

            //存在可抵扣的项目
            if (CollectionUtils.isNotEmpty(deductionAble)) {
                List<ItemBrokerageTechnicistDeduction> deductionDoneList = new ArrayList<>();
                List<ItemBrokerageTechnicist> xdeductionAble = new ArrayList<>();
                BigDecimal res = BigDecimal.ZERO;
                for (ItemBrokerageTechnicist deduction : deductionAble) {
                    if (defaultAmount.compareTo(BigDecimal.ZERO) != 1) {
                        break;
                    }
                    if (res.compareTo(BigDecimal.ZERO) == -1) {
                        res = deduction.getResidueAmount().subtract(res.negate());
                    }else {
                        res = deduction.getResidueAmount().subtract(defaultSequence.getBrokerageAmount());
                    }
                    //可抵扣减去预提的金额  剩余部分
                    //剩下为大于等于0
                    if (res.compareTo(BigDecimal.ZERO) != -1) {
                        ItemBrokerageTechnicistDeduction deductionDone = ItemBrokerageTechnicistDeduction.builder()
                                .brokerageSequenceId(defaultSequence.getId())
                                .brokerageTechnicistId(deduction.getId())
                                .deductionAmount(deduction.getResidueAmount().subtract(res))
                                .build();
                        deductionDoneList.add(deductionDone);
                        deduction.setResidueAmount(res);
                        xdeductionAble.add(deduction);
                        break;
                    } else {
                        ItemBrokerageTechnicistDeduction deductionDone = ItemBrokerageTechnicistDeduction.builder()
                                .brokerageSequenceId(defaultSequence.getId())
                                .brokerageTechnicistId(deduction.getId())
                                .deductionAmount(deduction.getResidueAmount())
                                .build();
                        deductionDoneList.add(deductionDone);
                        deduction.setResidueAmount(BigDecimal.ZERO);
                        xdeductionAble.add(deduction);
                    }
                }
                deductionService.saveBatch(deductionDoneList);
                technicistService.updateBatchById(xdeductionAble);
            }
        }
        return nonMarketerAheadAmounts.keySet();
    }

    //仅供单元测试用，后面删掉
    @Override
    public void extracted(BigDecimal defaultAmount, ItemBrokerageSequence defaultSequence, List<ItemBrokerageTechnicist> deductionAble) {
        if (CollectionUtils.isNotEmpty(deductionAble)) {
            List<ItemBrokerageTechnicistDeduction> deductionDoneList = new ArrayList<>();
            List<ItemBrokerageTechnicist> xdeductionAble = new ArrayList<>();
            BigDecimal res = BigDecimal.ZERO;
            for (ItemBrokerageTechnicist deduction : deductionAble) {
                if (defaultAmount.compareTo(BigDecimal.ZERO) != 1) {
                    break;
                }
                if (res.compareTo(BigDecimal.ZERO) == -1) {
                    res = deduction.getResidueAmount().subtract(res.negate());
                }else {
                    res = deduction.getResidueAmount().subtract(defaultSequence.getBrokerageAmount());
                }
                //可抵扣减去预提的金额  剩余部分
                //剩下为大于等于0
                if (res.compareTo(BigDecimal.ZERO) != -1) {
                    ItemBrokerageTechnicistDeduction deductionDone = ItemBrokerageTechnicistDeduction.builder()
                            .brokerageSequenceId(defaultSequence.getId())
                            .brokerageTechnicistId(deduction.getId())
                            .deductionAmount(defaultAmount)
                            .build();
                    deductionDoneList.add(deductionDone);
                    deduction.setResidueAmount(res);
                    xdeductionAble.add(deduction);
                    break;
                } else {
                    ItemBrokerageTechnicistDeduction deductionDone = ItemBrokerageTechnicistDeduction.builder()
                            .brokerageSequenceId(defaultSequence.getId())
                            .brokerageTechnicistId(deduction.getId())
                            .deductionAmount(deduction.getResidueAmount())
                            .build();
                    deductionDoneList.add(deductionDone);
                    deduction.setResidueAmount(BigDecimal.ZERO);
                    xdeductionAble.add(deduction);
                }
            }
            deductionService.saveBatch(deductionDoneList);
            technicistService.updateBatchById(xdeductionAble);
        }
    }



    /**
     * 结算可结算的项目提成
     * @return
     */
    @Transactional
    @Override
    public Set<Long>  doAbleItemBrokerageSettle() {
        List<ItemBrokerageGeneral> generals = brokerageGeneralService.computedAbleList();
        Map<Long, ItemBrokerageGeneral> idGeneral = generals.stream().collect(Collectors.toMap(BaseEntity::getId, ItemBrokerageGeneral -> ItemBrokerageGeneral));
        if (CollectionUtils.isNotEmpty(generals)){
            Set<Long> generalIds = generals.stream().map(ItemBrokerageGeneral::getId).collect(Collectors.toSet());
            List<ItemBrokerageDetail> settleDetails = brokerageDetailService.list(new LambdaQueryWrapper<ItemBrokerageDetail>()
                    .in(ItemBrokerageDetail::getGeneralId, generalIds).eq(BaseEntity::getDeleted, Boolean.FALSE));
            List<ItemBrokerageDetail> toUpdateItemBrokerageDetails = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(settleDetails)){
                Set<ItemBrokerageSequenceDetail> sequenceDetails = Sets.newHashSet();
                for (ItemBrokerageDetail x : settleDetails){
                    ItemBrokerageGeneral general = idGeneral.get(x.getGeneralId());
                    //客户经理 或者 营销主管 预提
                    if (general.getMarketerStatus().equals(BrokerageState.TO_PREDICTING.getCode())
                            && x.getBrokerageMode().equals(BrokerageMode.PERSONAL.getCode())
                            && (x.getBrokerageRule().equals(BrokerageRule.LAND_MARKETER_RULE.getCode()) ||x.getBrokerageRule().equals(BrokerageRule.LAND_SUPERVISOR_RULE.getCode()) )) {
                        ItemBrokerageSequenceDetail sequenceDetail = getAheadBrokerageForMarketer(x);
                        toUpdateItemBrokerageDetails.add(x);
                        sequenceDetails.add(sequenceDetail);
                    }
                    //项目全额回款后 营销主管或客户经理的结算
                    else if (general.getMarketerStatus().equals(BrokerageState.NOT_SETTLE.getCode())
                            && x.getBrokerageMode().equals(BrokerageMode.PERSONAL.getCode())
                            && ( x.getBrokerageRule().equals(BrokerageRule.LAND_MARKETER_RULE.getCode()) ||x.getBrokerageRule().equals(BrokerageRule.LAND_SUPERVISOR_RULE.getCode()) )) {
                        //减去已预提金额 ，这个地方需要再次根据 [结算时间节点] 去重新计算 营销主管或客户经理的 实际提成金额，因为 回款金额等因素可能有变动。
                        //客户经理的实际提成金额则根据预估计算时得出的金额为准
                        ItemBrokerageSequenceDetail sequenceDetail = getSettleBrokerageForMarketer(x);
                        toUpdateItemBrokerageDetails.add(x);
                        sequenceDetails.add(sequenceDetail);
                    }
                    // 2023/09/26 新增需求：一旦项目有回款，客户经理则当月结算回款部分的提成
                    else if (general.getMarketerStatus().equals(BrokerageState.NOT_PAYMENT.getCode())
                            && x.getBrokerageMode().equals(BrokerageMode.PERSONAL.getCode())
                            && (x.getBrokerageRule().equals(BrokerageRule.LAND_MARKETER_RULE.getCode())
                            ||x.getBrokerageRule().equals(BrokerageRule.LAND_SUPERVISOR_RULE.getCode()))){
                        List<ItemBrokerageSequenceDetail> sequenceDetailList = getPaymentForMarketer(general,x);
                        //已结算金额
                        BigDecimal advanceAmount = x.getAdvanceAmount();
                        // 多次回款金额求和
                        BigDecimal reduce = sequenceDetailList.stream().map(ItemBrokerageSequenceDetail::getBrokerageAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                        x.setAdvanceAmount(advanceAmount.add(reduce));
                        toUpdateItemBrokerageDetails.add(x);
                        sequenceDetails.addAll(sequenceDetailList);
                    }
                    //市场部领导的团队抽成部分，是跟具回款金额来结算，即使合同金额未完全回款，市场部领导的团队抽成部分也可以根据目前回款金额来结算。
                    else if( x.getBrokerageMode().equals(BrokerageMode.TEAM_SHARE.getCode())
                            && (x.getBrokerageRule().equals(BrokerageRule.LAND_MANAGER_RULE.getCode())
                            || x.getBrokerageRule().equals(LAND_SUPERVISOR_RULE.getCode()))){
                        Map<Boolean, List<BrokerageVariable>> leaderSettles = leaderBrokerageHandle(x);
                        if (leaderSettles==null){
                            continue;
                        }
                        List<BrokerageVariable> coll = leaderSettles.get(Boolean.TRUE);
                        List<BrokerageVariable> variables = leaderSettles.get(Boolean.FALSE);
                        if (CollectionUtils.isNotEmpty(coll)){
                            compensationSettle(sequenceDetails, x, coll);
                        }
                        if (CollectionUtils.isNotEmpty(variables)){
                            newPaymentSettle(sequenceDetails, x, variables);
                        }
                        toUpdateItemBrokerageDetails.add(x);
                    }
                    else if (general.getParticipantStatus().equals(BrokerageState.NOT_SETTLE.getCode()) && x.getBrokerageRule().equals(BrokerageRule.LAND_OTHER_RULE.getCode())) {
                        ItemBrokerageSequenceDetail sequenceDetail = otherRuleSettle(x,general.getItemId());
                        toUpdateItemBrokerageDetails.add(x);
                        sequenceDetails.add(sequenceDetail);
                    }
                }
                Map<Long, List<ItemBrokerageSequenceDetail>> collect = sequenceDetails.stream().filter(x->x!=null).collect(Collectors.groupingBy(ItemBrokerageSequenceDetail::getUserId));
                Date now = new Date();
                int year = DateUtils.getYear(now);
                int month = DateUtils.getMonth(now);
                Set<Long> marketers = userService.usersByDepartment(MARKET_DEPARTMENT).stream().map(IdNameVO::getId).collect(Collectors.toSet());
                List<String> landTechDepartments = Arrays.stream(LandTechDepartmentEnum.values()).map(LandTechDepartmentEnum::getName).collect(Collectors.toList());
                List<IdNameVO> landTechUsers = userService.usersByDepartments(landTechDepartments);
                for (Map.Entry<Long,List<ItemBrokerageSequenceDetail>> userSequence : collect.entrySet()){
                    List<ItemBrokerageSequenceDetail> values = userSequence.getValue();
                    Set<Long> itemSize = values.stream().map(ItemBrokerageSequenceDetail::getGeneralId).collect(Collectors.toSet());
                    BigDecimal userTotalAmount = values.stream().map(ItemBrokerageSequenceDetail::getBrokerageAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    Long userId = userSequence.getKey();
                    //todo 以后需优化  人员岗位分化
                    if (marketers.contains(userId)){
                        //市场人员直接结算
                        ItemBrokerageSequence sequence = ItemBrokerageSequence.builder().brokerageAmount(userTotalAmount).userId(userId)
                                .cate(BrokerageBusiness.ITEM_SETTLE.getCode())
                                .remark(BROKERAGE_SEQUENCE_REMARK.replace("sum",String.valueOf(itemSize.size())))
                                .embody(BROKERAGE_SEQUENCE_EMBODY.replace(YEARMONTH,year+"-"+month))
                                .year(year)
                                .month(month)
                                .build();
                        this.save(sequence);
                        values.stream().forEach(x->{x.setSequenceId(sequence.getId());});
                        brokerageSequenceDetailService.saveBatch(values);
                    }else if(landTechUsers.contains(userId)){
                        //技术人员 转移奖金池
                        ItemBrokerageSequence sequence = ItemBrokerageSequence.builder().brokerageAmount(userTotalAmount).userId(userId)
                                .cate(BrokerageBusiness.POOL_SETTLE.getCode())
                                .remark(POOL_SETTLE_REMARK)
                                .embody(BROKERAGE_POOL_EMBODY.replace(YEARMONTH,year+"-"+month))
                                .year(year)
                                .month(month)
                                .build();
                        this.save(sequence);
                        values.stream().forEach(x->{x.setSequenceId(sequence.getId());});
                        //技术人员提成汇总
                       doTechnicistBrokerageCollect(userSequence,sequence.getId());
                        brokerageSequenceDetailService.saveBatch(values);
                    }
                }
                brokerageDetailService.updateBatchById(toUpdateItemBrokerageDetails);

                Map<Long, List<ItemBrokerageSequenceDetail>> sequenceDetailByGeneral = sequenceDetails.stream().filter(x->x!=null).collect(Collectors.groupingBy(ItemBrokerageSequenceDetail::getGeneralId));

                for (Map.Entry<Long,List<ItemBrokerageSequenceDetail>> sequence : sequenceDetailByGeneral.entrySet()){
                    ItemBrokerageGeneral general = idGeneral.get(sequence.getKey());
                    BigDecimal reduce = sequence.getValue().stream().map(ItemBrokerageSequenceDetail::getBrokerageAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    general.setBrokerageActualAmount(reduce.add(general.getBrokerageActualAmount()));

                    if (general.getMarketerStatus().equals(BrokerageState.TO_PREDICTING.getCode())){
                        general.setMarketerAdvanceBrokerageDone(Boolean.TRUE);
                        general.setMarketerStatus(BrokerageState.NOT_PAYMENT.getCode());
                    }
                    if (general.getMarketerStatus().equals(BrokerageState.NOT_SETTLE.getCode())){
                        general.setMarketerStatus(BrokerageState.CLOSED.getCode());
                    }
                    if (general.getParticipantStatus().equals(BrokerageState.NOT_SETTLE.getCode())){
                        general.setParticipantStatus(BrokerageState.CLOSED.getCode());
                        general.setParticipantAdvanceStatus(Boolean.FALSE);
                    }
                }
                log.info("结算完成.");
                brokerageGeneralService.updateBatchById(generals);
                Set<Long> settleUserIds = collect.keySet();
                return settleUserIds;
            }

        }
        log.info("当前暂无可结算的项目");
        return null;
    }

    /**
     * 客户经理非全额回款结算逻辑
     * @param general
     * @return
     */
    private List<ItemBrokerageSequenceDetail> getPaymentForMarketer(ItemBrokerageGeneral general,ItemBrokerageDetail brokerageDetail) {
        BigDecimal brokerageRate = general.getBrokerageRate();
        BigDecimal advanceAmount = brokerageDetail.getAdvanceAmount();
        BigDecimal actualAmount = brokerageDetail.getActualAmount();
        List<PaymentCollection> paymentCollections = brokerageMarketerSettledMapper.getNotSettledPayment(general.getItemId());
        List<ItemBrokerageSequenceDetail> collect = Lists.newArrayList();
        for (PaymentCollection paymentCollection : paymentCollections){
            //此笔回款提成金额
            BigDecimal brokerageAmount = landMarketerBrokerageHandler.marketerPaymentAmount(paymentCollection, brokerageRate);
            if (advanceAmount.add(brokerageAmount).compareTo(actualAmount)<=0){
                ItemBrokerageSequenceDetail build = ItemBrokerageSequenceDetail.builder().brokerageAmount(brokerageAmount)
                        .unsettledAmount(BigDecimal.ZERO).paymentId(paymentCollection.getId()).brokerageCate(BrokerageBusiness.PAYMENT_SETTLE.getCode())
                        .userId(brokerageDetail.getUserId()).brokerageDetailId(brokerageDetail.getId()).generalId(general.getId()).build();
                collect.add(build);
                advanceAmount = advanceAmount.add(brokerageAmount);
            }else {
                ItemBrokerageSequenceDetail build = ItemBrokerageSequenceDetail.builder().brokerageAmount(actualAmount.subtract(advanceAmount))
                        .unsettledAmount(BigDecimal.ZERO).paymentId(paymentCollection.getId()).brokerageCate(BrokerageBusiness.PAYMENT_SETTLE.getCode())
                        .userId(brokerageDetail.getUserId()).brokerageDetailId(brokerageDetail.getId()).generalId(general.getId()).build();
                collect.add(build);
                break;
            }
        }
        //记录已结算的回款
        List<BrokerageMarketerSettled> settledPayments = paymentCollections.stream().map(x -> {
            BrokerageMarketerSettled brokerageMarketerSettled = new BrokerageMarketerSettled();
            brokerageMarketerSettled.setPaymentId(x.getId());
            return brokerageMarketerSettled;
        }).collect(Collectors.toList());
        brokerageMarketerSettledService.saveBatch(settledPayments);
        return collect;
    }

    /**
     * 技术人员的提成在项目维度汇总
     * @param userSequence
     */
    private void doTechnicistBrokerageCollect(Map.Entry<Long, List<ItemBrokerageSequenceDetail>> userSequence,Long sequenceId) {
        Long userId = userSequence.getKey();
        List<ItemBrokerageSequenceDetail> sequenceValue = userSequence.getValue();
        List<ItemBrokerageTechnicist> itemBrokerages = Lists.newArrayList();



        Map<Long, List<ItemBrokerageSequenceDetail>> collectByItemId = sequenceValue.stream().collect(Collectors.groupingBy(ItemBrokerageSequenceDetail::getItemId));
        for (Map.Entry<Long,List<ItemBrokerageSequenceDetail>> item : collectByItemId.entrySet()){
            BigDecimal brokerageTotal = item.getValue().stream().map(ItemBrokerageSequenceDetail::getBrokerageAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            ItemBrokerageTechnicist itemBrokerage = ItemBrokerageTechnicist.builder()
                    .itemId(item.getKey())
                    .userId(userId)
                    .sequenceId(sequenceId)
                    .amount(brokerageTotal)
                    .residueAmount(brokerageTotal)
                    .build();
            itemBrokerages.add(itemBrokerage);
        }
        technicistService.saveBatch(itemBrokerages);
        List<ItemBrokerageTechnicist> technicistsBrokerages = technicistService.list(new LambdaQueryWrapper<ItemBrokerageTechnicist>().eq(ItemBrokerageTechnicist::getUserId, userId).gt(ItemBrokerageTechnicist::getResidueAmount,BigDecimal.ZERO));
        //检查是否存在预提记录，产生真实提成需冲抵技术人员预提记录
        List<DeductionDTO> deductionDTOS = deductionMapper.notDeductionDefaultSettle(userId);

        //技术人员提成抵扣
        itemBrokerageSequenceService.deduction(technicistsBrokerages, deductionDTOS);

    }


    /**
     * 技术人员的默认预提与项目结算抵扣逻辑
     * @param itemBrokerages
     * @param deductionDTOS
     */
    @Transactional
    @Override
    public void deduction(List<ItemBrokerageTechnicist> itemBrokerages, List<DeductionDTO> deductionDTOS) {
        BigDecimal res = null;
        Long sequenceId = null;
        BigDecimal notDeduAmount = null;
        int j = 0;
        List<ItemBrokerageTechnicistDeduction> newDeductions = new ArrayList<>();
        List<ItemBrokerageTechnicist> updateTechnicists = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(deductionDTOS)){
            for (ItemBrokerageTechnicist deductionAble : itemBrokerages){
                //余数大于等于0
                if (res!=null && res.compareTo(BigDecimal.ZERO)!=-1){
                    // 未抵扣的已抵扣完 退出外层循环
                    break;
                }
                else {
                    //在外循环中一直抵扣
                    if (res!=null && res.compareTo(BigDecimal.ZERO) == -1){
                        res = deductionAble.getResidueAmount().subtract(res.negate());
                        if (res!=null && res.compareTo(BigDecimal.ZERO) == -1){
                            ItemBrokerageTechnicistDeduction allDeduction = ItemBrokerageTechnicistDeduction.builder()
                                    .brokerageTechnicistId(deductionAble.getId()).brokerageSequenceId(sequenceId).deductionAmount(deductionAble.getResidueAmount()).build();
                            deductionAble.setResidueAmount(BigDecimal.ZERO);
                            newDeductions.add(allDeduction);
                            updateTechnicists.add(deductionAble);
                            continue;
                        }
                        ItemBrokerageTechnicistDeduction departDeduction = ItemBrokerageTechnicistDeduction.builder()
                                .brokerageTechnicistId(deductionAble.getId()).brokerageSequenceId(sequenceId).deductionAmount(deductionAble.getResidueAmount().subtract(res)).build();
                        newDeductions.add(departDeduction);
                        //减去外循环中已抵扣的一部分，重新设置余额再进入内循环抵扣
                        deductionAble.setResidueAmount(res);
                    }
                    //在外循环中某一笔抵扣完上一笔还有剩余，进入内循环中抵扣
                    for (int i =j;i<deductionDTOS.size(); i++){
                        //余数小于0
                        if (res!=null && res.compareTo(BigDecimal.ZERO) == -1){
                            res = deductionAble.getResidueAmount().subtract(res.negate());
                            //余数大于等于0
                            if (res!=null && res.compareTo(BigDecimal.ZERO)!=-1){
                                //继续内循环中抵扣 插入
                                ItemBrokerageTechnicistDeduction allDeduction = ItemBrokerageTechnicistDeduction.builder()
                                        .brokerageTechnicistId(deductionAble.getId()).brokerageSequenceId(sequenceId).deductionAmount(notDeduAmount).build();
                                deductionAble.setResidueAmount(res);
                                newDeductions.add(allDeduction);
                                updateTechnicists.add(deductionAble);
                                continue;
                            }else {
                                //说明外层循环可抵扣的值不足，调出内层循环
                                ItemBrokerageTechnicistDeduction departDeduction = ItemBrokerageTechnicistDeduction.builder()
                                        .brokerageTechnicistId(deductionAble.getId()).brokerageSequenceId(sequenceId).deductionAmount(res.negate()).build();
                                deductionAble.setResidueAmount(BigDecimal.ZERO);
                                newDeductions.add(departDeduction);
                                updateTechnicists.add(deductionAble);
                                j = i+1;
                                break;
                            }
                        }
                        else {
                            sequenceId = deductionDTOS.get(i).getSequenceId();
                            notDeduAmount = deductionDTOS.get(i).getNotDeduAmount();
                            res = deductionAble.getResidueAmount().subtract(notDeduAmount);
                            //余数大于等于0
                            if (res!=null && res.compareTo(BigDecimal.ZERO)!=-1){
                                //继续内循环中抵扣 插入 (完全抵扣完)
                                ItemBrokerageTechnicistDeduction allDeduction = ItemBrokerageTechnicistDeduction.builder()
                                        .brokerageTechnicistId(deductionAble.getId()).brokerageSequenceId(sequenceId).deductionAmount(notDeduAmount).build();
                                deductionAble.setResidueAmount(res);
                                newDeductions.add(allDeduction);
                                updateTechnicists.add(deductionAble);
                                continue;
                            }
                            else {
                                //说明外层循环可抵扣的值不足，调出内层循环 (部分抵扣完)
                                ItemBrokerageTechnicistDeduction departDeduction = ItemBrokerageTechnicistDeduction.builder()
                                        .brokerageTechnicistId(deductionAble.getId()).brokerageSequenceId(sequenceId).deductionAmount(notDeduAmount.subtract(res.negate())).build();
                                deductionAble.setResidueAmount(BigDecimal.ZERO);
                                newDeductions.add(departDeduction);
                                updateTechnicists.add(deductionAble);
                                j = i+1;
                                break;
                            }
                        }
                    }
                    updateTechnicists.add(deductionAble);
                }
            }
        }
        deductionService.saveBatch(newDeductions);
        technicistService.updateBatchById(updateTechnicists);
    }

    /**
     * 参与人人员结算
     * @param x
     * @return
     */
    private ItemBrokerageSequenceDetail otherRuleSettle(ItemBrokerageDetail x,Long itemId) {
        ItemBrokerageSequenceDetail sequenceDetail = ItemBrokerageSequenceDetail.builder()
                .brokerageDetailId(x.getId()).unsettledAmount(BigDecimal.ZERO).userId(x.getUserId())
                .brokerageCate(BrokerageBusiness.SETTLE.getCode()).brokerageAmount(x.getActualAmount()).generalId(x.getGeneralId()).itemId(itemId).build();
        x.setAdvanceAmount(x.getActualAmount());
        return sequenceDetail;
    }

    /**
     * 市场部领导新增回款结算
     * @param sequenceDetails
     * @param x
     * @param variables
     */
    private void newPaymentSettle(Set<ItemBrokerageSequenceDetail> sequenceDetails, ItemBrokerageDetail x, List<BrokerageVariable> variables) {
        List<ItemBrokerageSequenceDetail> newPayments = variables.stream().map(v -> {
            ItemBrokerageSequenceDetail sequenceDetail = ItemBrokerageSequenceDetail.builder()
                    .brokerageDetailId(x.getId())
                    .userId(x.getUserId())
                    .brokerageCate(BrokerageBusiness.PAYMENT_SETTLE.getCode())
                    .brokerageAmount(v.getSettledAmount())
                    .unsettledAmount(v.getUnsettledAmount())
                    .paymentId(v.getPaymentId())
                    .generalId(x.getGeneralId()).build();
            return sequenceDetail;
        }).collect(Collectors.toList());

        BigDecimal reduce = variables.stream().map(BrokerageVariable::getSettledAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        x.setAdvanceAmount(x.getAdvanceAmount().add(reduce));
        x.setActualAmount(x.getActualAmount().add(reduce));
        sequenceDetails.addAll(newPayments);
    }

    /**
     * 市场部领导补偿结算
     * @param sequenceDetails
     * @param x
     * @param coll
     */
    private void compensationSettle(Set<ItemBrokerageSequenceDetail> sequenceDetails, ItemBrokerageDetail x, List<BrokerageVariable> coll) {
        List<ItemBrokerageSequenceDetail> compensations = coll.stream().map(v -> {
            ItemBrokerageSequenceDetail sequenceDetail = ItemBrokerageSequenceDetail.builder()
                    .brokerageDetailId(v.getBrokerageDetailId())
                    .userId(x.getUserId())
                    .brokerageCate(BrokerageBusiness.COMPENSATION.getCode())
                    .brokerageAmount(v.getUnsettledAmount())
                    .unsettledAmount(BigDecimal.ZERO)
                    .paymentId(v.getPaymentId())
                    .generalId(x.getGeneralId())
                    .build();
            return sequenceDetail;
        }).collect(Collectors.toList());

        BigDecimal reduce = coll.stream().map(BrokerageVariable::getUnsettledAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        x.setAdvanceAmount(x.getAdvanceAmount().add(reduce));
        x.setActualAmount(x.getActualAmount().add(reduce));
        sequenceDetails.addAll(compensations);

        //更新补偿结算表
        coll.stream().forEach(c->{
            c.setUnsettledAmount(BigDecimal.ZERO);
            c.setSettledAmount(c.getBrokerageAmount());
        });
        brokerageVariableService.updateBatchById(coll);
    }

    /**
     * 合同状态为待结算，处理客户经理或营销主管的结算逻辑(合同金额全额回款后才结算客户经理提成逻辑，单笔回款不结算，一次性结算所有)
     * @param x
     * @return
     */
    private ItemBrokerageSequenceDetail getSettleBrokerageForMarketer(ItemBrokerageDetail x) {
        BigDecimal actualAmount = x.getActualAmount();
        // 减去已结算金额
        actualAmount = actualAmount.subtract(x.getAdvanceAmount());
        ItemBrokerageSequenceDetail sequenceDetail = ItemBrokerageSequenceDetail.builder()
                .brokerageDetailId(x.getId()).userId(x.getUserId()).brokerageCate(BrokerageBusiness.SETTLE.getCode())
                .brokerageAmount(actualAmount).unsettledAmount(BigDecimal.ZERO).generalId(x.getGeneralId()).build();
        x.setAdvanceAmount(x.getActualAmount());
        x.setActualAmount(x.getActualAmount());
        return sequenceDetail;
    }

    /**
     * 合同状态为待预提，处理客户经理预提逻辑
     * @param x
     * @return
     */
    private ItemBrokerageSequenceDetail getAheadBrokerageForMarketer(ItemBrokerageDetail x) {
        ItemBrokerageSequenceDetail sequenceDetail = ItemBrokerageSequenceDetail.builder()
                .brokerageDetailId(x.getId()).userId(x.getUserId()).brokerageCate(BrokerageBusiness.AHEAD.getCode()).brokerageAmount(x.getAheadAmount())
                .unsettledAmount(x.getPredictAmount().subtract(x.getAheadAmount())).generalId(x.getGeneralId()).build();
        x.setAdvanceAmount(x.getAheadAmount());
        return sequenceDetail;
    }

    /**
     * 处理领导的提成逻辑 (包含两部分：1由于回款目标达成的补偿结算 （True），2,新增回款的结算 (False))
     * @param brokerageDetail
     * @return
     */
    private Map<Boolean,List<BrokerageVariable>> leaderBrokerageHandle(ItemBrokerageDetail brokerageDetail) {

        ItemDTO item = brokerageGeneralService.getItemByBrokerageGeneralId(brokerageDetail.getGeneralId());
        if (item==null){
            return null;
        }
        ItemBrokerageGeneral general = brokerageGeneralService.getById(brokerageDetail.getGeneralId());
        Map<Boolean,List<BrokerageVariable>> map = new HashMap<>();
                //团队回款目标
        BigDecimal teamPaymentTarget = BigDecimal.valueOf(userTargetService.getTeamTarget(brokerageDetail.getUserId()).getPaymentTarget());
        BigDecimal teamCurrentYearPayment = marketStatService.currentYearTeamPayment(brokerageDetail.getUserId());

        if (marketerBrokerageHandler.checkTeamMonthlyPayment(teamCurrentYearPayment, teamPaymentTarget)){
            List<BrokerageVariable>  compensations = compensationBrokerage(brokerageDetail.getUserId(),brokerageDetail.getGeneralId());
            if (CollectionUtils.isNotEmpty(compensations)){
                map.put(Boolean.TRUE,compensations);
            }
        }

        //这个方法要获取 新增的 且未被结算过的回款 。
        List<PaymentDetailDTO> list = brokerageVariableService.getPaymentDetailListByItemId(item.getId(),brokerageDetail.getUserId());
        if (CollectionUtils.isNotEmpty(list)){
            BrokeragePostRatio postRatio = brokeragePostRatioService.getOne(new LambdaQueryWrapper<BrokeragePostRatio>()
                    .eq(BrokeragePostRatio::getBrokerageRule, brokerageDetail.getBrokerageRule()).eq(BaseEntity::getDeleted, Boolean.FALSE));
            if (postRatio!=null && postRatio.getBrokerageRatio()!=null){
                List<BrokerageVariable> newPayments = list.stream().map(x->{
                    if (LAND_SUPERVISOR_RULE.getCode().equals(brokerageDetail.getBrokerageRule())){
                        return  landMarketerBrokerageHandler.supervisorSettle(x.getPaymentId(), x.getPaymentAmount(), brokerageDetail.getUserId(), postRatio.getBrokerageRatio(), general.getBrokerageRate());
                    }else{
                        return landMarketerBrokerageHandler.managerSettle(x.getPaymentId(),x.getPaymentAmount(),item.getUserId(),brokerageDetail.getUserId(),postRatio.getBrokerageRatio());
                    }
                }).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(newPayments)){
                    brokerageVariableService.saveBatch(newPayments);
                    map.put(Boolean.FALSE,newPayments);
                }

            }
        }
        return map;
    }

    /**
     * 回款目标达到时，结算以前未结算的提成部分
     * @return
     */
    private List<BrokerageVariable>  compensationBrokerage(Long userId,Long generalId){
        List<BrokerageVariable> list = brokerageVariableService.getCompensationBrokerage(userId,generalId);
        return list;
    }


    @Override
    public List<BrokerageSequenceVO> deduction(BrokerageSequenceVO brokerageSequenceVO) {
        List<BrokerageSequenceVO> list = brokerageSequenceMapper.deduction(brokerageSequenceVO);
        return list;
    }

    @Override
    public List<BrokerageSequenceVO> xList(BrokerageSequenceVO brokerageSequenceVO) {
        List<BrokerageSequenceVO> list =  brokerageSequenceMapper.xList(brokerageSequenceVO);
        return list;
    }
}
