package com.czg.service.market.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopInfo;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.UserInfo;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.account.service.UserInfoService;
import com.czg.constant.TableValueConstant;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkDistributionUserDTO;
import com.czg.market.dto.MkDistributionWithdrawFlowDTO;
import com.czg.market.entity.*;
import com.czg.market.service.*;
import com.czg.market.vo.DistributionCenterShopVO;
import com.czg.market.vo.DistributionCenterTopVO;
import com.czg.market.vo.InviteUserVO;
import com.czg.market.vo.MkDistributionConfigVO;
import com.czg.order.dto.MkDistributionPayDTO;
import com.czg.order.entity.OrderInfo;
import com.czg.sa.StpKit;
import com.czg.service.market.enums.OrderStatusEnums;
import com.czg.service.market.mapper.MkDistributionUserMapper;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgRandomUtils;
import com.czg.utils.FunUtils;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 分销员表 服务层实现。
 *
 * @author ww
 * @since 2025-10-27
 */
@Slf4j
@Service
public class MkDistributionUserServiceImpl extends ServiceImpl<MkDistributionUserMapper, MkDistributionUser> implements MkDistributionUserService {

    @Resource
    private MkDistributionGroupService mkDistributionGroupService;
    @Resource
    private MkDistributionConfigService mkDistributionConfigService;
    @Resource
    private MkDistributionLevelConfigService levelConfigService;
    @Resource
    private MkDistributionAmountFlowService distributionAmountFlowService;
    @Resource
    private MkDistributionFlowService distributionFlowService;
    @Resource
    private MkDistributionWithdrawFlowService withdrawFlowService;
    @Resource
    private MkDistributionDeliverService distributionDeliverService;
    @Resource
    private MkDistributionInviteService distributionInviteService;
    @Resource
    private AppWxServiceImpl appWxService;
    @DubboReference
    private ShopUserService shopUserService;
    @DubboReference
    private UserInfoService userInfoService;
    @Resource
    private OrderInfoService orderInfoService;
    @DubboReference
    private ShopInfoService shopInfoService;

    @Override
    public Map<String, Object> centerUser(Long userId) {
        DistributionCenterTopVO centerTopVO = null;
        try {
            QueryWrapper totalIncomeSumQueryWrapper = new QueryWrapper();
            totalIncomeSumQueryWrapper.select("sum(total_income) as totalIncome,sum(pending_income) as pendingIncome,sum(withdrawn_income) as cashOutAmount");
            totalIncomeSumQueryWrapper.eq(MkDistributionUser::getUserId, userId);
            totalIncomeSumQueryWrapper.eq(MkDistributionUser::getIsDel, 0);
            centerTopVO = getOneAs(totalIncomeSumQueryWrapper, DistributionCenterTopVO.class);
        } catch (Exception e) {
            log.error("查询用户中心数据失败", e);
        }
        // 封装顶部收益数据
        UserInfo userInfo = userInfoService.getById(userId);
        Map<String, Object> result = new HashMap<>(5);
        result.put("totalIncome", centerTopVO == null ? 0.0 : centerTopVO.getTotalIncome());
        result.put("pendingIncome", centerTopVO == null ? 0.0 : centerTopVO.getPendingIncome());
        result.put("cashOutAmount", userInfo.getDistributionAmount());

        result.put("activates", activates(userId, 1, 5));
        result.put("unActivates", unActivates(userId, 1, 3));
        return result;
    }

    @Override
    public Page<DistributionCenterShopVO> activates(Long userId, Integer page, Integer size) {
        PageHelper.startPage(page, size);
        List<DistributionCenterShopVO> activates = mapper.selectMyDistributionShops(userId);
        return PageUtil.convert(new PageInfo<>(activates));
    }

    @Override
    public Page<DistributionCenterShopVO> unActivates(Long userId, Integer page, Integer size) {
        PageHelper.startPage(page, size);
        List<DistributionCenterShopVO> unActivates = mapper.selectUnDistributionShops(userId);
        for (DistributionCenterShopVO unActivate : unActivates) {
            if (unActivate.getOrderCount() == 1) {
                unActivate.setLabelContent("在本店下单过");
            } else if (unActivate.getShopUser() == 1) {
                unActivate.setLabelContent("曾进入过店铺");
            }
//            else if("manual".equals(unActivate.getOpenType())){
//                unActivate.setLabelContent("manual手动开通");，
//            }

        }
        return PageUtil.convert(new PageInfo<>(unActivates));
    }


    @Override
    public Map<String, Object> centerConfig(Long userId, Long shopId) {
        Map<String, Object> result = new HashMap<>();
        ShopInfo shopInfo = shopInfoService.getById(shopId);
        AssertUtil.isNull(shopInfo, "店铺不存在");
        result.put("shopName", shopInfo.getShopName());
        result.put("parentName", "");
        result.put("parentPhone", "");
        ShopUser shopUser = shopUserService.getShopUserInfo(shopId, userId);
        AssertUtil.isNull(shopUser, "店铺用户不存在");
        UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
        result.put("cashOutAmount", userInfo.getDistributionAmount() == null ? 0.0 : userInfo.getDistributionAmount());
        MkDistributionInvite invite = distributionInviteService.getByShopIdAndShopUserId(shopId, shopUser.getId());
        if (invite != null && invite.getParentUserId() != null) {
            MkDistributionUser mkDistributionUser = getMkDistributionUserByIdAndShopId(invite.getParentUserId(), shopId);
            AssertUtil.isNull(mkDistributionUser, "上级分销员不存在");
            ShopUser shopUserParent = shopUserService.getById(mkDistributionUser.getId());
            result.put("parentName", shopUserParent.getNickName());
            result.put("parentPhone", shopUserParent.getPhone());
        }
        MkDistributionUser mkDistributionUser = getMkDistributionUserByIdAndShopId(shopUser.getId(), shopId);
        MkDistributionConfigVO mkDistributionConfigVO = mkDistributionConfigService.detail(shopId);
        MkDistributionGroup group = mkDistributionGroupService.getById(shopId);
        result.put("config", mkDistributionConfigVO);
        result.put("group", group);
        if (mkDistributionUser != null) {
            Map<String, Object> distributionUser = new HashMap<>();
            distributionUser.put("distributionId", mkDistributionUser.getId());
            distributionUser.put("inviteCode", mkDistributionUser.getInviteCode());
            distributionUser.put("consumeAmount", mkDistributionUser.getConsumeAmount());
            distributionUser.put("status", mkDistributionUser.getStatus() == 9);
            distributionUser.put("totalIncome", mkDistributionUser.getTotalIncome());
            distributionUser.put("pendingIncome", mkDistributionUser.getPendingIncome());
            distributionUser.put("isAssignLevel", mkDistributionUser.getIsAssignLevel());
            distributionUser.put("firstIn", mkDistributionUser.getFirstIn());

            if (mkDistributionUser.getDistributionLevelId() != null) {
                List<MkDistributionLevelConfig> levelConfigList = mkDistributionConfigVO.getLevelConfigList();
                boolean isNextLevel = false;
                for (MkDistributionLevelConfig levelConfig : levelConfigList) {
                    if ("invite".equals(mkDistributionConfigVO.getUpgradeType()) && isNextLevel) {
                        distributionUser.put("nextLevelGap", levelConfig.getInviteCount() - mkDistributionUser.getInviteCount());
                        break;
                    }
                    if (levelConfig.getId().equals(mkDistributionUser.getDistributionLevelId())) {
                        distributionUser.put("level", levelConfig.getLevel());
                        distributionUser.put("levelName", levelConfig.getName());
                        distributionUser.put("levelOneCommission", levelConfig.getCommission());
                        isNextLevel = true;
                    }
                }
            } else {
                distributionUser.put("level", 0);
                distributionUser.put("levelName", "无");
            }
            result.put("distributionUser", distributionUser);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String getInviteCode(Long shopId, Long shopUserId) throws CzgException, ValidateException {
        ShopUser shopUser = shopUserService.getById(shopUserId);
        AssertUtil.isNull(shopUser, "店铺用户不存在");
        MkDistributionConfigVO mkDistributionConfigVO = mkDistributionConfigService.detail(shopId);
        if (mkDistributionConfigVO == null || mkDistributionConfigVO.getIsEnable() == 0) {
            throw new CzgException("店铺分销功能未开启");
        }
        MkDistributionUser mkDistributionUser = getMkDistributionUserByIdAndShopId(shopUser.getId(), shopId);
        if (mkDistributionUser == null) {
            if (!"auto".equals(mkDistributionConfigVO.getOpenType())) {
                throw new CzgException("该店铺不可自行成为分销员");
            }
            mkDistributionUser = new MkDistributionUser();
            mkDistributionUser.setId(shopUser.getId());
            mkDistributionUser.setShopId(shopId);
            mkDistributionUser.setOpeningMethod("自主申请");
            mkDistributionUser = addDistributionUser(mkDistributionUser);
        }
        return mkDistributionUser.getInviteCode();
    }

    @Override
    public void realNameAuth(UserInfo userInfo) {
        AssertUtil.isTrue(!IdcardUtil.isValidCard(userInfo.getIdCard()), "身份证号格式错误");
        UserInfo newUserInfo = new UserInfo();
        newUserInfo.setId(userInfo.getId());
        newUserInfo.setRealName(userInfo.getRealName());
        newUserInfo.setIdCard(userInfo.getIdCard());
        userInfoService.updateById(newUserInfo);
    }

    @Override
    @GlobalTransactional
    public void bindInviteUser(MkDistributionUserDTO param) throws CzgException, ValidateException {
        ShopUser shopUser = shopUserService.getById(param.getId());
        AssertUtil.isNull(shopUser, "店铺用户不存在");
        MkDistributionInvite shopUserInvite = distributionInviteService.getByShopIdAndShopUserId(param.getShopId(), shopUser.getId());
        if (shopUserInvite != null && shopUserInvite.getParentUserId() != null) {
            throw new CzgException("店铺用户已存在上级");
        }
        MkDistributionUser parent = getOne(QueryWrapper.create().eq(MkDistributionUser::getInviteCode, param.getInviteCode()));
        AssertUtil.isNull(parent, "邀请人不存在");
        if (!parent.getShopId().equals(param.getShopId())) {
            throw new CzgException("邀请人不是本店铺的分销员");
        }
        if (parent.getId().equals(shopUser.getId())) {
            throw new CzgException("不能绑定自己为上级");
        }
        if (parent.getStatus() == 9) {
            throw new CzgException("绑定失败该邀请人分销身份已被取消");
        }
        ShopUser parentShopUser = shopUserService.getById(parent.getId());
        AssertUtil.isNull(parentShopUser, "邀请人不存在");
        MkDistributionInvite parentShopUserInvite = distributionInviteService.getByShopIdAndShopUserId(param.getShopId(), parentShopUser.getId());
        if (parentShopUserInvite != null && parentShopUserInvite.getParentUserId() != null && parentShopUserInvite.getParentUserId().equals(shopUser.getId())) {
            throw new CzgException("存在绑定关系，不可绑定");
        }
        if (parentShopUserInvite != null && parentShopUserInvite.getGradeUserId() != null && parentShopUserInvite.getGradeUserId().equals(shopUser.getId())) {
            throw new CzgException("存在绑定关系，不可绑定");
        }

        //更新自己的上级
        MkDistributionInvite newShopUserInvite = new MkDistributionInvite();
        newShopUserInvite.setShopId(param.getShopId());
        newShopUserInvite.setUserId(shopUser.getUserId());
        newShopUserInvite.setShopUserId(shopUser.getId());
        newShopUserInvite.setParentUserId(parentShopUser.getId());
        newShopUserInvite.setGradeUserId(parentShopUserInvite == null ? null : parentShopUserInvite.getParentUserId());
        newShopUserInvite.setInviteTime(LocalDateTime.now());
        distributionInviteService.save(newShopUserInvite);
        if (parentShopUserInvite != null && parentShopUserInvite.getParentUserId() != null) {
            //更新自己的下级 的上级的上级 为自己的上级
            MkDistributionInvite childShopUserInvite = new MkDistributionInvite();
            childShopUserInvite.setGradeUserId(parentShopUser.getId());
            distributionInviteService.update(childShopUserInvite, QueryWrapper.create().eq(MkDistributionInvite::getParentUserId, shopUser.getId()));
        }

        MkDistributionUser newDistributionUser = new MkDistributionUser();
        newDistributionUser.setId(parent.getId());
        newDistributionUser.setInviteCount(parent.getInviteCount() + 1);
        MkDistributionConfig mkDistributionConfig = mkDistributionConfigService.getOne(QueryWrapper.create()
                .eq(MkDistributionConfig::getShopId, parent.getShopId()));
        if ("自主申请".equals(parent.getOpeningMethod()) && parent.getStatus() == 0 && mkDistributionConfig != null) {
            if (newDistributionUser.getInviteCount() >= mkDistributionConfig.getInviteCount()) {
                ShopUser parentShopUser1 = new ShopUser();
                parentShopUser1.setId(parentShopUser.getId());
                parentShopUser1.upDistributionShop(param.getShopId(), 1);
                shopUserService.updateById(parentShopUser1);
            }
        }
        if (mkDistributionConfig != null && !"not_upgrade".equals(mkDistributionConfig.getUpgradeType()) && parent.getIsAssignLevel() == 0) {
            if ("invite".equals(mkDistributionConfig.getUpgradeType())) {
                if (mkDistributionConfig.getInviteConsume() == 1) {
                    long count = orderInfoService.count(QueryWrapper.create()
                            .eq(OrderInfo::getUserId, shopUser.getUserId())
                            .eq(OrderInfo::getShopId, parent.getShopId())
                            .eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode()));
                    if (count < 1) {
                        throw new CzgException("绑定失败,被邀请人需要成功支付一笔订单");
                    }
                }
                MkDistributionLevelConfig levelConfig = levelConfigService.getOne(QueryWrapper.create()
                        .eq(MkDistributionLevelConfig::getShopId, parent.getShopId())
                        .le(MkDistributionLevelConfig::getInviteCount, newDistributionUser.getInviteCount())
                        .orderBy(MkDistributionLevelConfig::getId).desc().limit(1));
                if (levelConfig != null) {
                    newDistributionUser.setDistributionLevelId(levelConfig.getId());
                    newDistributionUser.setDistributionLevelName(levelConfig.getName());
                    newDistributionUser.setStatus(1);
                }
            } else if ("cost".equals(mkDistributionConfig.getUpgradeType())) {
                costUpgradeLevel(parent.getId(), parent.getShopId());
            }
        }
        update(newDistributionUser, QueryWrapper.create().eq(MkDistributionUser::getId, parent.getId())
                .eq(MkDistributionUser::getShopId, parent.getShopId()));
    }

    @Override
    @GlobalTransactional
    public void bindInviteUser(Long fromUserId, Long toUserId, Long shopId) throws CzgException, ValidateException {
        ShopUser shopUser = shopUserService.getById(toUserId);
        AssertUtil.isNull(shopUser, "店铺用户不存在");
        MkDistributionInvite shopUserInvite = distributionInviteService.getByShopIdAndShopUserId(shopId, shopUser.getId());
        if (shopUserInvite != null && shopUserInvite.getParentUserId() != null) {
            throw new CzgException("店铺用户已存在上级");
        }
        MkDistributionUser parent = getOne(QueryWrapper.create().eq(MkDistributionUser::getId, fromUserId).eq(MkDistributionUser::getShopId, shopId));
        AssertUtil.isNull(parent, "邀请人不存在");
        if (parent.getId().equals(shopUser.getId())) {
            throw new CzgException("不能绑定自己为上级");
        }
        if (parent.getStatus() == 9) {
            throw new CzgException("绑定失败该邀请人分销身份已被取消");
        }
        ShopUser parentShopUser = shopUserService.getById(parent.getId());
        AssertUtil.isNull(parentShopUser, "邀请人不存在");

        MkDistributionInvite parentShopUserInvite = distributionInviteService.getByShopIdAndShopUserId(shopId, parentShopUser.getId());
        if (parentShopUserInvite != null && parentShopUserInvite.getParentUserId() != null && parentShopUserInvite.getParentUserId().equals(shopUser.getId())) {
            throw new CzgException("存在绑定关系，不可绑定");
        }
        if (parentShopUserInvite != null && parentShopUserInvite.getGradeUserId() != null && parentShopUserInvite.getGradeUserId().equals(shopUser.getId())) {
            throw new CzgException("存在绑定关系，不可绑定");
        }

        //更新自己的上级
        MkDistributionInvite newShopUserInvite = new MkDistributionInvite();
        newShopUserInvite.setShopId(shopId);
        newShopUserInvite.setUserId(shopUser.getUserId());
        newShopUserInvite.setShopUserId(shopUser.getId());
        newShopUserInvite.setParentUserId(parentShopUser.getId());
        newShopUserInvite.setGradeUserId(parentShopUserInvite == null ? null : parentShopUserInvite.getParentUserId());
        newShopUserInvite.setInviteTime(LocalDateTime.now());
        distributionInviteService.save(newShopUserInvite);
        if (parentShopUserInvite != null && parentShopUserInvite.getParentUserId() != null) {
            //更新自己的下级 的上级的上级 为自己的上级
            MkDistributionInvite childShopUserInvite = new MkDistributionInvite();
            childShopUserInvite.setGradeUserId(parentShopUser.getId());
            distributionInviteService.update(childShopUserInvite, QueryWrapper.create().eq(MkDistributionInvite::getParentUserId, shopUser.getId()));
        }

        MkDistributionUser newDistributionUser = new MkDistributionUser();
        newDistributionUser.setId(parent.getId());
        newDistributionUser.setInviteCount(parent.getInviteCount() + 1);
        MkDistributionConfig mkDistributionConfig = mkDistributionConfigService.getOne(QueryWrapper.create()
                .eq(MkDistributionConfig::getShopId, parent.getShopId()));
        if ("自主申请".equals(parent.getOpeningMethod()) && parent.getStatus() == 0 && mkDistributionConfig != null) {
            if (newDistributionUser.getInviteCount() >= mkDistributionConfig.getInviteCount()) {
                ShopUser parentShopUser1 = new ShopUser();
                parentShopUser1.setId(parentShopUser.getId());
                parentShopUser1.upDistributionShop(shopId, 1);
                shopUserService.updateById(parentShopUser1);
            }
        }
        if (mkDistributionConfig != null && !"not_upgrade".equals(mkDistributionConfig.getUpgradeType()) && parent.getIsAssignLevel() == 0) {
            if ("invite".equals(mkDistributionConfig.getUpgradeType())) {
                if (mkDistributionConfig.getInviteConsume() == 1) {
                    long count = orderInfoService.count(QueryWrapper.create()
                            .eq(OrderInfo::getUserId, shopUser.getUserId())
                            .eq(OrderInfo::getShopId, parent.getShopId())
                            .eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode()));
                    if (count < 1) {
                        throw new CzgException("绑定失败,被邀请人需要成功支付一笔订单");
                    }
                }
                MkDistributionLevelConfig levelConfig = levelConfigService.getOne(QueryWrapper.create()
                        .eq(MkDistributionLevelConfig::getShopId, parent.getShopId())
                        .le(MkDistributionLevelConfig::getInviteCount, newDistributionUser.getInviteCount())
                        .orderBy(MkDistributionLevelConfig::getId).desc().limit(1));
                if (levelConfig != null) {
                    newDistributionUser.setDistributionLevelId(levelConfig.getId());
                    newDistributionUser.setDistributionLevelName(levelConfig.getName());
                    newDistributionUser.setStatus(1);
                }
            } else if ("cost".equals(mkDistributionConfig.getUpgradeType())) {
                costUpgradeLevel(parent.getId(), parent.getShopId());
            }
        }
        update(newDistributionUser, QueryWrapper.create().eq(MkDistributionUser::getId, parent.getId())
                .eq(MkDistributionUser::getShopId, parent.getShopId()));
    }

    @Override
    public void costUpgradeLevelBefore(Long userId, Long shopId) {
        ShopUser shopUser = shopUserService.getShopUserInfo(shopId, userId);
        costUpgradeLevel(shopUser.getId(), shopId);
        MkDistributionInvite shopUserInvite = distributionInviteService.getByShopIdAndShopUserId(shopId, shopUser.getId());
        if (shopUserInvite != null && shopUserInvite.getParentUserId() != null) {
            costUpgradeLevel(shopUserInvite.getParentUserId(), shopId);
        }
    }


    /**
     * 分销员：按消费金额升级等级
     */
    public void costUpgradeLevel(Long shopUserId, Long shopId) {
        MkDistributionUser distributionUser = getMkDistributionUserByIdAndShopId(shopUserId, shopId);
        if (distributionUser == null || distributionUser.getIsAssignLevel() == 1) {
            return;
        }
        MkDistributionConfig mkDistributionConfig = mkDistributionConfigService.getOne(QueryWrapper.create()
                .eq(MkDistributionConfig::getShopId, distributionUser.getShopId()));
        if (mkDistributionConfig == null || !"cost".equals(mkDistributionConfig.getUpgradeType())) {
            return;
        }
        BigDecimal totalAmount = mapper.getOrderConsumeAmountByList(shopId, distributionUser.getId());
        BigDecimal ownTotalAmount = mapper.getOrderConsumeAmountById(shopId, distributionUser.getUserId());
        totalAmount = totalAmount.add(ownTotalAmount);
        MkDistributionLevelConfig levelConfig = levelConfigService.getOne(QueryWrapper.create()
                .eq(MkDistributionLevelConfig::getShopId, distributionUser.getShopId())
                .le(MkDistributionLevelConfig::getCostAmount, totalAmount)
                .gt(MkDistributionLevelConfig::getId, distributionUser.getDistributionLevelId())
                .orderBy(MkDistributionLevelConfig::getId).desc().limit(1));
        MkDistributionUser newDistributionUser = new MkDistributionUser();
        newDistributionUser.setId(shopUserId);
        newDistributionUser.setConsumeAmount(totalAmount);
        if (levelConfig != null) {
            if (totalAmount.compareTo(levelConfig.getCostAmount()) >= 0) {
                newDistributionUser.setId(shopUserId);
                newDistributionUser.setDistributionLevelId(levelConfig.getId());
                newDistributionUser.setDistributionLevelName(levelConfig.getName());
            }
        }
        update(newDistributionUser, QueryWrapper.create().eq(MkDistributionUser::getId, shopUserId)
                .eq(MkDistributionUser::getShopId, shopId));

    }

    @Override
    public Page<MkDistributionUserDTO> getDistributionUser(MkDistributionUserDTO param) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(MkDistributionUser::getId, param.getId());
        queryWrapper.eq(MkDistributionUser::getShopId, param.getShopId());
        queryWrapper.ne(MkDistributionUser::getStatus, 0);
        queryWrapper.eq(MkDistributionUser::getDistributionLevelId, param.getDistributionLevelId());
        queryWrapper.ge(MkDistributionUser::getCreateTime, param.getStartTime());
        queryWrapper.le(MkDistributionUser::getCreateTime, param.getEndTime());
        queryWrapper.orderBy(MkDistributionUser::getCreateTime).desc();
        Page<MkDistributionUserDTO> page = pageAs(new Page<>(param.getPage(), param.getSize()), queryWrapper, MkDistributionUserDTO.class);
        Map<Long, ShopUser> shopUserMap = new HashMap<>();
        if (CollUtil.isNotEmpty(page.getRecords())) {
            if (param.getId() != null) {
                shopUserMap.put(param.getId(), shopUserService.getById(param.getId()));
            } else {
                Set<Long> shopUserIds = page.getRecords().stream()
                        .map(MkDistributionUserDTO::getId)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());
                List<ShopUser> shopUserList = shopUserService.list(QueryWrapper.create().in(ShopUser::getId, shopUserIds));
                if (CollUtil.isNotEmpty(shopUserList)) {
                    shopUserMap = shopUserList.stream().collect(Collectors.toMap(ShopUser::getId, shopUser -> shopUser));
                }
            }
            for (MkDistributionUserDTO record : page.getRecords()) {
                ShopUser shopUser = shopUserMap.get(record.getId());
                if (shopUser == null || shopUser.getId() == null) {
                    continue;
                }
                record.setHeadImg(shopUser.getHeadImg());
                record.setShopUserName(shopUser.getNickName());
                record.setShopUserPhone(shopUser.getPhone());
            }
        }
        return page;
    }

    @Override
    public Page<InviteUserVO> getInviteUser(Long id, Long shopId, Long shopUserId, Long distributionLevelId, Integer page, Integer size) {
        return shopUserService.getInviteUser(id, shopId, shopUserId, distributionLevelId, page, size);
    }

    @Override
    @GlobalTransactional
    public MkDistributionUser addDistributionUser(MkDistributionUser param) {
        AssertUtil.isNull(param.getShopId(), "店铺ID不能为空");
        AssertUtil.isNull(param.getOpeningMethod(), "开通方式不能为空");
        AssertUtil.isNull(param.getId(), "店铺用户ID不能为空");
        ShopUser shopUser = shopUserService.getById(param.getId());
        AssertUtil.isNull(shopUser, "店铺用户ID不能为空");
        MkDistributionUser distributionUser = getMkDistributionUserByIdAndShopId(param.getId(), param.getShopId());
        if (distributionUser != null && distributionUser.getStatus() != 0) {
            throw new CzgException("该用户已是分销员,不可重复添加");
        }
        MkDistributionConfig config = mkDistributionConfigService.getOne(
                QueryWrapper.create().eq(MkDistributionConfig::getShopId, param.getShopId())
                        .eq(MkDistributionConfig::getIsEnable, 1));
        AssertUtil.isNull(config, "店铺未配置分销");
        param.setStatus(0);
        param.setInviteCount(0);
        if (!"自主申请".equals(param.getOpeningMethod()) || config.getInviteCount() == 0) {
            initLevel(config, param);
        }
        if (distributionUser != null) {
            distributionUser.setOpeningMethod("手动添加");
            distributionUser.setDistributionLevelId(param.getDistributionLevelId());
            distributionUser.setDistributionLevelName(param.getDistributionLevelName());
            distributionUser.setStatus(1);
            update(distributionUser, QueryWrapper.create().eq(MkDistributionUser::getId, param.getId())
                    .eq(MkDistributionUser::getShopId, param.getShopId()));
        } else {
            if ("手动添加".equals(param.getOpeningMethod())) {
                param.setStatus(1);
            }
            param.setId(param.getId());
            param.setUserId(shopUser.getUserId());
            param.setInviteCode(CzgRandomUtils.randomString(10));
            save(param);
        }
        ShopUser shopUser2 = new ShopUser();
        shopUser2.setId(shopUser.getId());
        if (param.getStatus() == 0) {
            shopUser2.upDistributionShop(param.getShopId(), 0);
        } else {
            shopUser2.upDistributionShop(param.getShopId(), 1);
        }
        shopUserService.updateById(shopUser2);
        return param;
    }

    @Override
    public void updateDistributionUserById(MkDistributionUserDTO param) {
        AssertUtil.isNull(param.getId(), "分销员ID不能为空");
        MkDistributionUser distributionUser = BeanUtil.toBean(param, MkDistributionUser.class);
        update(distributionUser, QueryWrapper.create().eq(MkDistributionUser::getId, param.getId())
                .eq(MkDistributionUser::getShopId, param.getShopId()));
    }

    @Override
    public void resetDistributionUserLevel(MkDistributionUserDTO param) {
        AssertUtil.isNull(param.getId(), "分销员ID不能为空");
        MkDistributionUser distributionUser = getMkDistributionUserByIdAndShopId(param.getId(), param.getShopId());
        AssertUtil.isNull(distributionUser, "分销员不存在");
        AssertUtil.isTrue(distributionUser.getIsAssignLevel() == 0, "分销员并未指定等级,不可重置");
        MkDistributionConfig config = mkDistributionConfigService.getOne(
                QueryWrapper.create().eq(MkDistributionConfig::getShopId, param.getShopId())
                        .eq(MkDistributionConfig::getIsEnable, 1));
        AssertUtil.isNull(config, "店铺未配置分销");
        initLevel(config, distributionUser);
        MkDistributionUser newDistributionUser = new MkDistributionUser();
        newDistributionUser.setId(distributionUser.getId());
        newDistributionUser.setIsAssignLevel(0);
        newDistributionUser.setDistributionLevelId(distributionUser.getDistributionLevelId());
        newDistributionUser.setDistributionLevelName(distributionUser.getDistributionLevelName());
        newDistributionUser.setConsumeAmount(distributionUser.getConsumeAmount());
        update(newDistributionUser, QueryWrapper.create().eq(MkDistributionUser::getId, distributionUser.getId())
                .eq(MkDistributionUser::getShopId, distributionUser.getShopId()));
    }


    @Override
    public void initLevel(MkDistributionConfig config, MkDistributionUser distributionUser) {
        MkDistributionLevelConfig levelConfig = new MkDistributionLevelConfig();
        if ("not_upgrade".equals(config.getUpgradeType())) {
            levelConfig = levelConfigService.getOne(QueryWrapper.create()
                    .eq(MkDistributionLevelConfig::getShopId, config.getShopId())
                    .orderBy(MkDistributionLevelConfig::getId).asc().limit(1));
        } else if ("invite".equals(config.getUpgradeType())) {
            levelConfig = levelConfigService.getOne(QueryWrapper.create()
                    .eq(MkDistributionLevelConfig::getShopId, config.getShopId())
                    .le(MkDistributionLevelConfig::getInviteCount, distributionUser.getInviteCount())
                    .orderBy(MkDistributionLevelConfig::getInviteCount).desc().limit(1));
        } else if ("cost".equals(config.getUpgradeType())) {
            BigDecimal totalAmount = mapper.getOrderConsumeAmountByList(config.getShopId(), distributionUser.getId());
            BigDecimal ownTotalAmount = mapper.getOrderConsumeAmountById(config.getShopId(), distributionUser.getUserId());
            totalAmount = totalAmount.add(ownTotalAmount);
            levelConfig = levelConfigService.getOne(QueryWrapper.create()
                    .eq(MkDistributionLevelConfig::getShopId, distributionUser.getShopId())
                    .le(MkDistributionLevelConfig::getCostAmount, totalAmount)
                    .orderBy(MkDistributionLevelConfig::getId).desc().limit(1));
            distributionUser.setConsumeAmount(totalAmount);
        }
        if (levelConfig != null) {
            distributionUser.setDistributionLevelId(levelConfig.getId());
            distributionUser.setDistributionLevelName(levelConfig.getName());
            distributionUser.setStatus(1);
        } else {
            distributionUser.setDistributionLevelId(0L);
            distributionUser.setDistributionLevelName("无等级");
        }
        distributionUser.setIsAssignLevel(0);
    }

    @Override
    public void deleteDistributionUser(Long id, Long shopId) {
        AssertUtil.isNull(id, "分销员ID不能为空");
        MkDistributionUser distributionUser = new MkDistributionUser();
        distributionUser.setIsDel(1);
        update(distributionUser, QueryWrapper.create().eq(MkDistributionUser::getId, id)
                .eq(MkDistributionUser::getShopId, shopId));
    }


    @Override
    public Boolean cashPayOrder(long adminId, MkDistributionPayDTO payParam) {
        ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
        AssertUtil.isNull(shopInfo, "店铺不存在");
        BigDecimal amount = shopInfoService.updateAmount(shopInfo.getId(), payParam.getAmount());
        Long mainShopId = shopInfoService.getMainIdByShopId(shopInfo.getId());

        distributionAmountFlowService.save(new MkDistributionAmountFlow()
                .setType(payParam.getAmount().compareTo(BigDecimal.ZERO) < 0 ? TableValueConstant.DistributionAmountFlow.Type.MANUAL_SUB.getCode() :
                        TableValueConstant.DistributionAmountFlow.Type.MANUAL_RECHARGE.getCode())
                .setMainShopId(mainShopId).setShopId(shopInfo.getId()).setAmount(amount).setChangeAmount(payParam.getAmount())
                .setRemark(payParam.getRemark()).setOpAccount(StpKit.USER.getAccount()));
        return true;
    }

    @Override
    public void open(Long shopUserId, BigDecimal amount, Long shopId, Long sourceId) {
        ShopUser shopUserInfo = shopUserService.getById(shopUserId);
        Long mainShopId = shopInfoService.getMainIdByShopId(shopId);
//        BigDecimal finalAmount = shopInfoService.updateAmount(shopId, amount);
        distributionAmountFlowService.save(new MkDistributionAmountFlow()
                .setType(TableValueConstant.DistributionAmountFlow.Type.OPEN.getCode())
                .setMainShopId(mainShopId).setShopId(shopId).setAmount(amount).setChangeAmount(amount).setSourceId(sourceId)
                .setRemark("分销员购买"));
        try {
            addDistributionUser(new MkDistributionUser().setShopId(shopId)
                    .setUserId(shopUserInfo.getUserId())
                    .setId(shopUserInfo.getId()).setOpeningMethod("付费开通"));
        } catch (Exception e) {
            log.error("分销员开通失败", e);
        }
    }


    @Override
    public void rechargeCallBack(Long shopId, BigDecimal amount, Long paymentId) {
        Long mainShopId = shopInfoService.getMainIdByShopId(shopId);
        BigDecimal finalAmount = shopInfoService.updateAmount(shopId, amount);
        distributionAmountFlowService.save(new MkDistributionAmountFlow()
                .setType(TableValueConstant.DistributionAmountFlow.Type.SELF_RECHARGE.getCode())
                .setMainShopId(mainShopId).setShopId(shopId).setAmount(finalAmount).setChangeAmount(amount).setSourceId(paymentId)
                .setRemark("自助充值"));
    }


    @GlobalTransactional
    protected boolean deepReward(ShopUser orderSourceShopUser, BigDecimal commission, MkDistributionConfigVO config,
                                 MkDistributionUser currentDistributionUser, BigDecimal amount, Long sourceId,
                                 String type, String orderNo, Integer currentLevel) {
        // 当前分销员
        AssertUtil.isNull(currentDistributionUser, "分销员不存在");
        AssertUtil.isTrue(currentDistributionUser.getStatus() != 1, "分销员未开启");
        if (commission.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }
        // 金额
        BigDecimal rewardAmount = amount.multiply(commission.divide(BigDecimal.valueOf(100))).setScale(2, RoundingMode.FLOOR);
        if (rewardAmount.compareTo(new BigDecimal("0.01")) < 0) {
            return false;
        }

        if (config.getRewardCount() != null && config.getRewardCount() > 0) {
            long count = distributionFlowService.count(new QueryWrapper()
                    .eq(MkDistributionFlow::getShopId, config.getShopId()).eq(MkDistributionFlow::getShopUserId, currentDistributionUser.getId()));
            if (count >= config.getRewardCount()) {
                log.info("分销员{}已达到奖励次数上限, 次数: {}", currentDistributionUser.getId(), config.getRewardCount());
                return false;
            }
        }

        // 延时发放时间
        LocalDateTime delayTime = config.getSettlementDay() == null || config.getSettlementDay() == 0 ? null : DateUtil.offsetDay(DateUtil.date(), config.getSettlementDay()).toLocalDateTime();
        // 用户分账明细
        ShopUser shopUser = shopUserService.getById(currentDistributionUser.getId());
        MkDistributionFlow mkDistributionFlow = new MkDistributionFlow().setShopUserId(currentDistributionUser.getId())
                .setShopId(currentDistributionUser.getShopId()).setDistributionUserId(currentDistributionUser.getId())
                .setUserId(shopUser.getUserId())
                .setNickName(shopUser.getNickName()).setSourceShopUserId(orderSourceShopUser.getId()).setSourceNickName(orderSourceShopUser.getNickName())
                .setCommission(commission)
                .setLevelId(currentDistributionUser.getDistributionLevelId()).setLevel(currentLevel).setOrderNo(orderNo)
                .setSourceId(sourceId).setAmount(amount).setType(type)
                .setRewardAmount(rewardAmount).setBillNo(IdUtil.simpleUUID());

        if (delayTime == null) {
            mkDistributionFlow.setStatus(TableValueConstant.DistributionFlow.Status.SUCCESS.getCode());
            distributionFlowService.save(mkDistributionFlow);
            log.info("即时分销开始");
            try {
                updateShopInfoAmount(currentDistributionUser.getShopId(), rewardAmount.negate(), sourceId, TableValueConstant.DistributionAmountFlow.Type.SUB, "分销扣除");
                updateIncome(BigDecimal.ZERO, rewardAmount, BigDecimal.ZERO, currentDistributionUser.getId(), shopUser.getUserId(), shopUser.getId(), config.getShopId(), currentLevel == 1 ? 1 : 2);
            } catch (Exception e) {
                mkDistributionFlow.setStatus(TableValueConstant.DistributionFlow.Status.PENDING.getCode());
                updateIncome(rewardAmount, BigDecimal.ZERO, BigDecimal.ZERO, currentDistributionUser.getId(), shopUser.getUserId(), shopUser.getId(), config.getShopId(), currentLevel == 1 ? 1 : 2);
                distributionFlowService.updateById(mkDistributionFlow);
            }
        } else {
            mkDistributionFlow.setDeliverTime(delayTime);
            mkDistributionFlow.setStatus(TableValueConstant.DistributionFlow.Status.PENDING.getCode());
            distributionFlowService.save(mkDistributionFlow);
            log.info("延时分销开始");
            updateIncome(rewardAmount, BigDecimal.ZERO, BigDecimal.ZERO, currentDistributionUser.getId(), shopUser.getUserId(), shopUser.getId(), config.getShopId(), currentLevel == 1 ? 1 : 2);
        }
        return true;
    }

    @Override
    public BigDecimal updateShopInfoAmount(Long shopId, BigDecimal changeAmount, Long sourceId, TableValueConstant.DistributionAmountFlow.Type type, String remark) {
        BigDecimal finalAmount = shopInfoService.updateAmount(shopId, changeAmount);
        distributionAmountFlowService.save(new MkDistributionAmountFlow()
                .setType(type.getCode())
                .setShopId(shopId).setAmount(finalAmount).setChangeAmount(changeAmount).setSourceId(sourceId)
                .setRemark(remark));
        return finalAmount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refund(Long orderId, String orderNo) {
        boolean exists = distributionFlowService.exists(new QueryWrapper()
                .eq(MkDistributionFlow::getOrderNo, orderNo)
                .eq(MkDistributionFlow::getStatus, TableValueConstant.DistributionFlow.Status.REFUND.getCode()));
        if (exists) {
            log.warn("此分销已经退款");
            return;
        }

        List<MkDistributionFlow> list = distributionFlowService.list(new QueryWrapper()
                .eq(MkDistributionFlow::getOrderNo, orderNo)
                .ne(MkDistributionFlow::getStatus, TableValueConstant.DistributionFlow.Status.REFUND.getCode()));

        list.forEach(item -> {
            if (TableValueConstant.DistributionFlow.Status.PENDING.getCode().equals(item.getStatus())) {
                item.setStatus(TableValueConstant.DistributionFlow.Status.REFUND.getCode());
                distributionFlowService.updateById(item);
                mapper.updateIncome(item.getRewardAmount().negate(), null, null, item.getDistributionUserId(), item.getShopId());
            } else {
                // 执行扣款
                updateIncome(BigDecimal.ZERO, item.getRewardAmount().negate(), BigDecimal.ZERO, item.getDistributionUserId(), item.getUserId(), item.getShopUserId(), item.getShopId(), item.getLevel());
                updateShopInfoAmount(item.getShopId(), item.getRewardAmount(), orderId, TableValueConstant.DistributionAmountFlow.Type.REFUND, "分销回退");
            }
        });
    }

    @Transactional
    @Override
    public void distributionUserAmount(MkDistributionFlow item, OrderInfo orderInfo) {
        ShopUser shopUser = shopUserService.getById(item.getDistributionUserId());
        updateShopInfoAmount(orderInfo.getShopId(), item.getRewardAmount().negate(), orderInfo.getId(), TableValueConstant.DistributionAmountFlow.Type.SUB, "分销扣减");
        updateIncome(item.getRewardAmount().negate(), item.getRewardAmount(), BigDecimal.ZERO,
                item.getDistributionUserId(), shopUser.getUserId(), item.getShopUserId(), item.getShopId(), item.getLevel());
        distributionFlowService.updateById(item);
    }

    @Override
    public void distribute(Long sourceId, String orderNo, BigDecimal amount, Long sourceUserId, Long shopId, String type) {
        MkDistributionDeliver deliver = new MkDistributionDeliver().setSourceId(sourceId).setOrderNo(orderNo).setShopId(shopId).setType(type).setStatus("success");
        FunUtils.safeRunVoid(() -> {
            AssertUtil.isTrue(amount.compareTo(BigDecimal.ZERO) == 0, "分销金额不能为0");
            MkDistributionConfigVO config = mkDistributionConfigService.detail(shopId);
            AssertUtil.isTrue(config.getIsEnable() != 1, "分销未开启");
            // 产生消费的用户
            ShopUser curUser = shopUserService.getShopUserInfo(shopId, sourceUserId);
            MkDistributionInvite sourceInviteUser = distributionInviteService.getByShopIdAndShopUserId(shopId, curUser.getId());
            if (sourceInviteUser.getParentUserId() == null) {
                return;
            }

            log.info("开始分销, 当前来源用户: {}, shopId: {}, 邀请人id: {}", sourceUserId, shopId, sourceInviteUser.getParentUserId());

            MkDistributionUser distributionUser = getMkDistributionUserByIdAndShopId(sourceInviteUser.getParentUserId(), shopId);
            MkDistributionLevelConfig level = levelConfigService.getById(distributionUser.getDistributionLevelId());
            deepReward(curUser, level.getCommission(), config, distributionUser,
                    amount, sourceId, type, orderNo, 1);
            if (sourceInviteUser.getGradeUserId() != null) {
                MkDistributionUser parentDis = getMkDistributionUserByIdAndShopId(sourceInviteUser.getGradeUserId(), shopId);
                MkDistributionLevelConfig parentDisLevel = levelConfigService.getById(parentDis.getDistributionLevelId());
                deepReward(curUser, parentDisLevel.getCommission().subtract(level.getCommission()), config, parentDis,
                        amount, sourceId, type, orderNo, 2);
            }
        });
        distributionDeliverService.save(deliver);
    }

    /**
     * 分销金额修改
     *
     * @param pendingIncome  待入账金额
     * @param receivedIncome 已入账
     * @param withdrawIncome 已提现
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateIncome(BigDecimal pendingIncome, BigDecimal receivedIncome, BigDecimal withdrawIncome, Long id, Long userId, Long shopUserId, Long shopId, Integer isOne) {
        // 用户收益信息
        shopUserService.updateOneOrTwoAmount(shopUserId, shopId, receivedIncome, isOne);
        // 用户可提现余额
        userInfoService.updateDistributionAmount(userId, receivedIncome);
        //分销员余额
        boolean flag = mapper.updateIncome(pendingIncome, receivedIncome, withdrawIncome, id, shopId);
        if (!flag) {
            throw new CzgException("操作失败");
        }
    }

    @Override
    public Boolean withdraw(long userId, MkDistributionWithdrawFlowDTO withdrawFlowDTO) {
        UserInfo userInfo = userInfoService.getById(userId);
        if (userInfo.getDistributionAmount().subtract(withdrawFlowDTO.getAmount()).compareTo(BigDecimal.ZERO) < 0) {
            throw new CzgException("可提现金额不足");
        }

        if (StrUtil.isBlank(userInfo.getIdCard())) {
            throw new CzgException("请先实名认证");
        }

        BigDecimal fee = withdrawFlowDTO.getAmount().multiply(BigDecimal.valueOf(0.08)).setScale(2, RoundingMode.UP);
        BigDecimal finalAmount = withdrawFlowDTO.getAmount().subtract(fee);

        MkDistributionWithdrawFlow withdrawFlow = new MkDistributionWithdrawFlow().setUserId(userId)
                .setAmount(finalAmount).setServiceFee(fee).setBillNo(IdUtil.simpleUUID()).setStatus(TableValueConstant.DistributionWithdrawFlow.Status.PENDING.getCode());
        JSONObject jsonObject = appWxService.transferBalance(userInfo.getWechatOpenId(), userInfo.getRealName(), finalAmount, "提现", withdrawFlow.getBillNo());
        withdrawFlow.setPackageInfo(jsonObject.getString("package_info"));
        // 扣减余额
        userInfoService.updateDistributionAmount(userId, withdrawFlowDTO.getAmount().negate());
        return withdrawFlowService.save(withdrawFlow);
    }

    @Override
    public Map<String, Object> withdrawDetail(long userId, Long id) {
        MkDistributionWithdrawFlow flow = withdrawFlowService.getOne(new QueryWrapper().eq(MkDistributionWithdrawFlow::getId, id).eq(MkDistributionWithdrawFlow::getUserId, userId));
        AssertUtil.isNull(flow, "提现记录不存在");
        AssertUtil.isTrue(TableValueConstant.DistributionWithdrawFlow.Status.FINISH.getCode().equals(flow.getStatus()), "已经提现");

        return Map.of(
                "mchId", appWxService.config.mchId,
                "appId", appWxService.config.appId,
                "package", flow.getPackageInfo()
        );
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void withdrawNotify(String outBillNo, String state, String failReason) {
        MkDistributionWithdrawFlow flow = withdrawFlowService.getOne(new QueryWrapper().eq(MkDistributionWithdrawFlow::getBillNo, outBillNo));
        AssertUtil.isNull(flow, "提现记录不存在");
        switch (state) {
            case "SUCCESS":
                flow.setStatus(TableValueConstant.DistributionWithdrawFlow.Status.FINISH.getCode());
                break;
            case "FAIL":
                flow.setStatus(TableValueConstant.DistributionWithdrawFlow.Status.FAIL.getCode());
            case "CANCELLED":
                flow.setStatus(TableValueConstant.DistributionWithdrawFlow.Status.FAIL.getCode());
                // 扣减余额
                userInfoService.updateDistributionAmount(flow.getUserId(), flow.getAmount().add(flow.getServiceFee()));
                break;

        }
        flow.setFailReason(failReason);
        withdrawFlowService.updateById(flow);
    }

    @Override
    public MkDistributionUser getMkDistributionUserByIdAndShopId(Long shopUserId, Long shopId) {
        return getOne(new QueryWrapper().eq(MkDistributionUser::getId, shopUserId).eq(MkDistributionUser::getShopId, shopId));
    }
}
