package cn.newfeifan.mall.module.distri.service.sharepath;

import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.newfeifan.mall.module.distri.controller.admin.duser.vo.DuserSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.duser.DuserDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.ordercalc.OrderCalcDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.orderpercentage.OrderPercentageDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.socialstatus.SocialStatusDO;
import cn.newfeifan.mall.module.distri.dal.mysql.orderpercentage.OrderPercentageMapper;
import cn.newfeifan.mall.module.distri.enums.SocialStatusEnum;
import cn.newfeifan.mall.module.distri.service.duser.DuserService;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.ordercalc.OrderCalcService;
import cn.newfeifan.mall.module.distri.service.orderpercentage.OrderPercentageService;
import cn.newfeifan.mall.module.distri.service.socialstatus.SocialStatusService;
import cn.newfeifan.mall.module.distri.service.socialstatuschangelog.SocialStatusChangeLogService;
import cn.newfeifan.mall.module.member.controller.admin.user.vo.MemberUserRespVO;
import cn.newfeifan.mall.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
import cn.newfeifan.mall.module.member.convert.user.MemberUserConvert;
import cn.newfeifan.mall.module.member.dal.dataobject.user.MemberUserDO;
import cn.newfeifan.mall.module.member.service.user.MemberUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

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

import cn.newfeifan.mall.module.distri.controller.admin.sharepath.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.sharepath.SharePathDO;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.util.object.BeanUtils;

import cn.newfeifan.mall.module.distri.dal.mysql.sharepath.SharePathMapper;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.distri.constant.DistriConstants.BOOS_ID;
import static cn.newfeifan.mall.module.distri.constant.DistriConstants.PT_ID;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

/**
 * 分销用户关系 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class SharePathServiceImpl implements SharePathService {

    @Resource
    private SharePathMapper sharePathMapper;

    @Resource
    @Lazy
    private DuserService duserService;
    @Resource
    private MemberUserService memberUserService;
    @Resource
    @Lazy
    private OrderCalcService orderCalcService;

    @Resource
    @Lazy
    private IntegralService integralService;

    @Resource
    private SocialStatusChangeLogService socialStatusChangeLogService;

    @Resource
    private OrderPercentageMapper orderPercentageMapper;

    @Resource
    private SocialStatusService socialStatusService;
    @Resource
    private OrderPercentageService orderPercentageService;

    @Override
    public void createSharePathByUserId(SharePathSaveReqVO createReqVO, Boolean isNew) {

        // 如果直推人为空, 则直接结束
        if (createReqVO.getUserId() == null) {
            return;
        }

        // 判断当前直推人是否有父亲
        Boolean has = hasParent(createReqVO.getUserId());
        if (has) {
            throw exception(HAS_PARENT);
        }
        if (createReqVO.getReferrerId() == null) {
            createReqVO.setReferrerId(BOOS_ID);
        }
        MemberUserDO ancestor = memberUserService.getUser(createReqVO.getReferrerId());
        MemberUserDO descendant = memberUserService.getUser(createReqVO.getUserId());

        // 创建直推人以及推荐人的关系
        // 需要判断当前推荐人跟直推人是否已经存在于用户表(duser)了
        duserService.hasUserAndCreat(createReqVO);

        // 存储他们之间的关系
        if (!Objects.equals(createReqVO.getUserId(), PT_ID)) {
            sharePathMapper.addNode(
                    createReqVO.getReferrerId(),
                    ancestor.getUsername(),
                    null,
                    ancestor.getMobile(),

                    createReqVO.getUserId(),
                    descendant.getUsername(),
                    null,
                    descendant.getMobile());
        }

        if (!isNew) {
            return;
        }
        OrderPercentageDO orderPercentageDO = orderPercentageMapper.selectList().get(0);
        duserService.updateDuserSocial(createReqVO.getReferrerId(), Long.valueOf(orderPercentageDO.getRegisterAncestorSocialStatus()), SocialStatusEnum.REGISTER_ANCESTOR_SOCIAL.getStatus());
        socialStatusChangeLogService.createSocialStatusChangeLog(createReqVO.getReferrerId(), Long.valueOf(orderPercentageDO.getRegisterAncestorSocialStatus()), createReqVO.getReferrerId(), SocialStatusEnum.REGISTER_ANCESTOR_SOCIAL);

    }

    @Override
    public void createSharePathByUserId(List<Long> userIds) {

        for (Long userId : userIds) {
            Boolean has = hasParent(userId);
            if (has) {
                continue;
            }
            // 如果是没有父亲, 将其推荐人设置为平台
            SharePathSaveReqVO build = SharePathSaveReqVO.builder()
                    .referrerId(BOOS_ID)
                    .userId(userId)
                    .build();
            createSharePathByUserId(build, true);
        }
    }

    private Boolean hasParent(Long descendant) {
        List<SharePathDO> sharePathDO = sharePathMapper.selectList(new LambdaQueryWrapperX<SharePathDO>()
                .eqIfPresent(SharePathDO::getUserId, descendant));
        return !sharePathDO.isEmpty();
    }

    @Override
    public void updateSharePath(SharePathSaveReqVO updateReqVO) {
        // 校验存在
        validateSharePathExists(updateReqVO.getId());
        // 更新
        SharePathDO updateObj = BeanUtils.toBean(updateReqVO, SharePathDO.class);
        sharePathMapper.updateById(updateObj);
    }

    @Override
    public void deleteSharePath(Long id) {
        // 校验存在
        validateSharePathExists(id);
        // 删除
        sharePathMapper.deleteById(id);
    }

    private void validateSharePathExists(Long id) {
        if (sharePathMapper.selectById(id) == null) {
            throw exception(SHARE_PATH_NOT_EXISTS);
        }
    }

    @Override
    public SharePathDO getSharePath(Long id) {
        return sharePathMapper.selectById(id);
    }

    @Override
    public PageResult<SharePathDO> getSharePathPage(SharePathPageReqVO pageReqVO) {
        return sharePathMapper.selectPage(pageReqVO);
    }


    @Override
    public TreeNode getTree(Long userId, Integer maxDepth) {
        // 如果user为空, 则查询全部信息
        if (userId == null) {
            userId = PT_ID;
        }
        // 查询出第一层用户
        List<SharePathDO> sharePathDOS = sharePathMapper.selectListByUserId(userId, maxDepth);
        final Long userid = userId;
        SharePathDO sharePathDO = sharePathDOS.stream()
                .filter(k -> k.getUserId().equals(userid))
                .findFirst().get();

        // 转换后的对象
        List<TreeNode> treeNodes = sharePathDO2TreeNode(sharePathDOS);
        treeNodes = listWithTree(treeNodes, userId);

        TreeNode bean = BeanUtils.toBean(sharePathDO, TreeNode.class);
        bean.setChildren(treeNodes);
        return bean;
    }

    @Override
    public MemberUserRespVO getMemberUser(Long userId) {
        MemberUserDO user = memberUserService.getUser(userId);
        MemberUserRespVO memberUserRespVO = MemberUserConvert.INSTANCE.convert03(user);

        SharePathDO sharePathDO = sharePathMapper.selectOne(new LambdaQueryWrapper<SharePathDO>()
                .eq(SharePathDO::getUserId, userId)
        );
        if (sharePathDO != null) {
            SharePathDO referrer = sharePathMapper.selectOne(new LambdaQueryWrapper<SharePathDO>()
                    .eq(SharePathDO::getUserId, sharePathDO.getReferrerId())
            );
            if (referrer != null) {
                memberUserRespVO.setAncNickName(referrer.getUserName());
                memberUserRespVO.setRecommenderdId(referrer.getUserId());
            }
        }

        DuserDO duser = duserService.getDuserByUser(memberUserRespVO.getId());
        //没有这个用户直接就返回
        if (duser == null) return memberUserRespVO;
        memberUserRespVO.setCategoryId(duser.getCategoryId());

        IntegralDO integral = integralService.getIntegralByUserId(userId);
        if (integral != null) {
            memberUserRespVO.setRedCurrentQuota(integral.getRedCurrentQuota());
            memberUserRespVO.setYellowCurrentQuota(integral.getYellowCurrentQuota());
            memberUserRespVO.setGreenCurrentQuota(integral.getGreenCurrentQuota());
            memberUserRespVO.setHighQuotaTotal(integral.getHighQuotaTotal());
        }

        SocialStatusDO socialStatus = socialStatusService.getSocialStatus(duser.getSocialStatusId());
        if (socialStatus == null) return memberUserRespVO;
        memberUserRespVO.setCurrentMemberWorthLevelName(socialStatus.getName());
        memberUserRespVO.setCurrentMemberWorthLevel(socialStatus.getLevel());

        return memberUserRespVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(MemberUserUpdateReqVO updateReqVO) {
        // 判断当前用户是否更新推荐人
        Long ancestor = sharePathMapper.selectAncestorByDescendant(updateReqVO.getId());
        if (!Objects.equals(updateReqVO.getRecommenderdId(), ancestor)) {
            updateUserSharePath(updateReqVO.getId(), updateReqVO.getRecommenderdId());
        }

        DuserDO duser = duserService.getDuserByUser(updateReqVO.getId());
        if (!Objects.equals(duser.getCategoryId(), updateReqVO.getCategoryId())) {
            duser.setCategoryId(updateReqVO.getCategoryId());
            duserService.updateDuser(BeanUtils.toBean(duser, DuserSaveReqVO.class));
        }

        // 更新
        memberUserService.updateUser(updateReqVO);
    }

    @Override
    public PageResult<SharePathRespVO> getAreaChildren(SharePathPageReqVO pageReqVO) {

        PageResult<SharePathDO> sharePathDOPageResult = new PageResult<>();
        List<SharePathDO> sharePathDOS = sharePathMapper.selectListPage(pageReqVO.getAreaId(), pageReqVO.getPageSize(), (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
        List<SharePathDO> totals = sharePathMapper.selectListByUserId(pageReqVO.getAreaId(), 99999);

        sharePathDOPageResult.setList(sharePathDOS);
        sharePathDOPageResult.setTotal(totals == null ? 0L : totals.size());
        PageResult<SharePathRespVO> result = BeanUtils.toBean(sharePathDOPageResult, SharePathRespVO.class);
        List<SharePathRespVO> list = result.getList();
        list.forEach(sharePath -> sharePath.setAvatar(memberUserService.getUser(sharePath.getUserId()).getAvatar()));

        return result;
    }

    @Override
    public List<SharePathDO> selectList() {
        // 不算平台的
        return sharePathMapper.selectList(new LambdaQueryWrapper<SharePathDO>().ne(SharePathDO::getUserId, 1L));
    }

    @Override
    public Integer getReferrerNumber(Long userId) {
        return sharePathMapper.selectCount(new LambdaQueryWrapper<SharePathDO>().eq(SharePathDO::getReferrerId, userId)).intValue();
    }

    @Override
    public List<Long> getUserIds(Long userId, Integer maxDepth) {
        List<SharePathDO> sharePathDOS = sharePathMapper.selectListByUserId(userId, maxDepth);
        List<Long> collect = sharePathDOS.stream().map(SharePathDO::getUserId).collect(Collectors.toList());
        collect.remove(0);
        return collect;
    }

    /**
     * 更新用户关系网
     * @param userId 用户id
     * @param referrerId 推荐人id
     */
    private void updateUserSharePath(Long userId, Long referrerId) {
        // 获取当前用户的关系网
        SharePathDO user = sharePathMapper.selectOne(new LambdaQueryWrapper<SharePathDO>()
                .eq(SharePathDO::getUserId, userId));
        // 获取上级的关系网
        SharePathDO parent = sharePathMapper.selectOne(new LambdaQueryWrapper<SharePathDO>()
                .eq(SharePathDO::getUserId, user.getParentId()));

        // 去除上级用户的分区值
        if (parent.getLeftChildId() != null && parent.getLeftChildId().equals(user.getUserId())) {
            parent.setLeftChildId(null);
        } else {
            parent.setRightChildId(null);
        }
        LambdaUpdateWrapper<SharePathDO> wrapper = new LambdaUpdateWrapper<SharePathDO>().eq(SharePathDO::getUserId, parent.getUserId());
        if (parent.getLeftChildId() == null) {
            wrapper.set(SharePathDO::getLeftChildId, null);
        }
        if (parent.getRightChildId() == null) {
            wrapper.set(SharePathDO::getRightChildId, null);
        }
        sharePathMapper.update(parent, wrapper);

        // 获取推荐人的关系网
        SharePathDO referrer = sharePathMapper.selectOne(new LambdaQueryWrapper<SharePathDO>()
                .eq(SharePathDO::getUserId, referrerId));

        // 记录原来的层级
        Integer depth = user.getDepth();
        user.setReferrerId(referrerId);
        user.setDepth(referrer.getDepth() + 1);
        user.setParentId(referrerId);

        if (referrer.getLeftChildId() == null) {
            referrer.setLeftChildId(userId);
            sharePathMapper.update(referrer, new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, referrer.getUserId()));
        } else if (referrer.getRightChildId() == null) {    // 判断右区是否有空位
            referrer.setRightChildId(userId);
            sharePathMapper.update(referrer, new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, referrer.getUserId()));
        } else {
            // 左区列表
            List<SharePathDO> leftArea = sharePathMapper.selectListByUserId(referrer.getLeftChildId(), 99999);
            // 右区列表
            List<SharePathDO> rightArea = sharePathMapper.selectListByUserId(referrer.getRightChildId(), 99999);

            // 判断左右两区的节点数
            List<SharePathDO> list = leftArea.size() <= rightArea.size() ? leftArea : rightArea;
            for (SharePathDO sharePathDO : list) {
                if (sharePathDO.getLeftChildId() == null) {
                    user.setDepth(sharePathDO.getDepth() + 1);
                    user.setParentId(sharePathDO.getUserId());

                    sharePathDO.setLeftChildId(userId);
                    sharePathMapper.update(sharePathDO, new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, sharePathDO.getUserId()));
                    break;
                } else if (sharePathDO.getRightChildId() == null) {
                    user.setDepth(sharePathDO.getDepth() + 1);
                    user.setParentId(sharePathDO.getUserId());

                    sharePathDO.setRightChildId(userId);
                    sharePathMapper.update(sharePathDO, new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, sharePathDO.getUserId()));
                    break;
                }
            }
            sharePathMapper.updateById(user);
        }

        // 用户的关系网
        List<SharePathDO> userArea = sharePathMapper.selectListByUserId(userId, 99999);
        depth -= user.getDepth();

        // 遍历修改层级
        for (SharePathDO sharePathDO : userArea) {
            if (sharePathDO.getUserId().equals(userId)) {
                continue;
            }

            sharePathDO.setDepth(sharePathDO.getDepth() - depth);
        }
        sharePathMapper.updateBatch(userArea);
    }

    public List<TreeNode> sharePathDO2TreeNode(List<SharePathDO> sharePathDOS) {
        return sharePathDOS.stream().map(k -> TreeNode.builder()
                .phone(k.getPhone())
                .userName(k.getUserName())
                .depth(k.getDepth())
                .parentId(k.getParentId())
                .userId(k.getUserId())
                .referrerId(k.getReferrerId())
                .leftChildId(k.getLeftChildId())
                .rightChildId(k.getRightChildId()).build()).collect(Collectors.toList());
    }


    public static List<TreeNode> listWithTree(List<TreeNode> all, Long pid) {
        // 2、找到一级父类，再通过级联去查询儿子
        return all.stream().filter(k ->
                k.getParentId().equals(pid)   //查询父类
        ).map(k -> {
            k.setChildren(getChildren(k, all));
            return k;//查询子类菜单
        }).collect(Collectors.toList());
    }

    public static List<TreeNode> getChildren(TreeNode root, List<TreeNode> all) {
        // 递归查找所有后代的儿子
        return all.stream().filter(k -> k.getParentId().equals(root.getUserId()))
                .map(k -> {
                    k.setChildren(getChildren(k, all));
                    return k;
                }).collect(Collectors.toList());
    }

    @Override
    public void transferenceRela(SharePathtransFerenceRelaReqVO sharePathtransFerenceRelaReqVO) {
        // todo 转让用户关系
    }

    @Override
    public SharePathDO getSharePathByDescendant(Long userId) {
        return sharePathMapper.selectOne(new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, userId));
    }

    @Override
    public List<OrderCalcDO> selectArea(Long userId, List<Long> userIds) {
        List<SharePathDO> sharePathDOS = sharePathMapper.selectListByUserId(userId, 99999);
        List<Long> allDescendants = sharePathDOS.stream().map(SharePathDO::getUserId).collect(Collectors.toList());
        if (allDescendants.isEmpty()) {
            return Collections.emptyList();
        }
        // 查询出两个list的并集
        List<Long> unionList = unionList(userIds, allDescendants);
        if (unionList.isEmpty()) {
            return Collections.emptyList();
        }
        // 获取这个分区的所有订单的合赢奖
        return calcQuota(unionList);

    }

    private List<OrderCalcDO> calcQuota(List<Long> unionList) {

        // 根据当前userId， 查询当日，计算出来的订单
        // 创建日期
        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT); // 今天的开始时间，即午夜12点
        LocalDateTime todayEnd = todayStart.plusDays(1);

        return orderCalcService.queryTodayCalcByUserIds(todayStart, todayEnd, unionList);

    }

    @Override
    public Long queryParentBySonUserId(Long userId) {

        SharePathDO sharePathDO = sharePathMapper.selectOne(new LambdaQueryWrapperX<SharePathDO>()
                .eqIfPresent(SharePathDO::getUserId, userId));
        if (sharePathDO == null) {
            return 1L;
        } else {
            return sharePathDO.getParentId();
        }


    }

    @Override
    public List<DuserDO> selectSon(Long userId) {

        // 查询当前用户的所有后代
        List<SharePathDO> sharePathDOS = sharePathMapper.selectList(new LambdaQueryWrapperX<SharePathDO>().eqIfPresent(SharePathDO::getReferrerId, userId));

        List<Long> duserId = sharePathDOS.stream().map(SharePathDO::getUserId).collect(Collectors.toList());

        if (duserId.isEmpty()) {
            return Collections.emptyList();
        }

        return duserService.selectUserByUserIds(duserId);

    }

    @Override
    public List<Long> sonsId(Long userId) {
        List<SharePathDO> sharePathDOS = sharePathMapper.selectList(new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getReferrerId, userId));
        return sharePathDOS.stream().map(SharePathDO::getUserId).collect(Collectors.toList());

    }


    public List<Long> unionList(List<Long> orderUserId, List<Long> userId) {
        return userId.stream()
                .filter(orderUserId::contains)
                .collect(Collectors.toList());

//        return Stream.concat(orderUserId.stream(), userId.stream()).distinct().collect(Collectors.toList());

    }

    @Override
    public PageResult<SharePathRespVO> getDescendants(SharePathPageReqVO pageReqVO) {

        PageResult<SharePathDO> sharePathDOPageResult = sharePathMapper.selectDescendantsPage(pageReqVO);
        PageResult<SharePathRespVO> result = BeanUtils.toBean(sharePathDOPageResult, SharePathRespVO.class);
        List<SharePathRespVO> list = result.getList();
        list.forEach(sharePath -> sharePath.setAvatar(memberUserService.getUser(sharePath.getUserId()).getAvatar()));
        return result;
    }


}