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

import cn.newfeifan.mall.framework.common.pojo.PageParam;
import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.newfeifan.mall.module.distri.controller.app.sharepath.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.partitioncrash.PartitionCrashDO;
import cn.newfeifan.mall.module.distri.dal.mysql.partitioncrash.PartitionCrashMapper;
import cn.newfeifan.mall.module.distri.service.duser.DuserService;
import cn.newfeifan.mall.module.member.controller.admin.user.vo.MemberUserRespVO;
import cn.newfeifan.mall.module.member.service.user.MemberUserService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;


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 java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
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
    private PartitionCrashMapper partitionCrashMapper;

    @Override
    public void createSharePathByUserId(SharePathSaveReqVO createReqVO) {
        // 需要判断当前用户是否已经存在于关系表中
        duserService.hasUserAndCreat(createReqVO.getUserId());

        // 推荐人
        SharePathDO referrer = sharePathMapper.selectOne(new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, createReqVO.getReferrerId()));

        SharePathDO build = SharePathDO
                .builder()
                .depth(referrer.getDepth() + 1)
                .userId(createReqVO.getUserId())
                .parentId(createReqVO.getReferrerId())
                .referrerId(createReqVO.getReferrerId())
                .userName(createReqVO.getUserName())
                .phone(createReqVO.getPhone())
                .build();
        // 判断左区是否有空位
        if (referrer.getLeftChildId() == null) {
            sharePathMapper.insert(build);
            referrer.setLeftChildId(createReqVO.getUserId());
            sharePathMapper.update(referrer, new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, referrer.getUserId()));
        } else if (referrer.getRightChildId() == null) {    // 判断右区是否有空位
            sharePathMapper.insert(build);
            referrer.setRightChildId(createReqVO.getUserId());
            sharePathMapper.update(referrer, new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, referrer.getUserId()));
        } else {
            // 左区列表
            List<SharePathDO> leftArea = sharePathMapper.selectListByUserId(referrer.getLeftChildId());
            // 右区列表
            List<SharePathDO> rightArea = sharePathMapper.selectListByUserId(referrer.getRightChildId());

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

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

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

    @Override
    public void createSharePathByUserId(Long userId) {
        Boolean has = hasParent(userId);
        if (has) {
            return;
        }
        // 如果是没有父亲, 将其推荐人设置为平台
        SharePathSaveReqVO build = SharePathSaveReqVO.builder()
                .referrerId(PT_ID)
                .userId(userId)
                .build();
        createSharePathByUserId(build);
    }

    @Override
    public Boolean hasParent(Long userId) {
        SharePathDO sharePathDO = sharePathMapper.selectOne(new LambdaQueryWrapperX<SharePathDO>()
                .eqIfPresent(SharePathDO::getUserId, userId));
        return sharePathDO != null;
    }

    @Override
    public AppSharePathRespVO getTeam(PageParam pageParam) {
        Long userId = getLoginUserId();

        SharePathDO sharePathDO = sharePathMapper.selectOne(new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, userId));
//        MemberUserRespVO parentUser = BeanUtils.toBean(memberUserService.getUser(sharePathDO.getParentId()), MemberUserRespVO.class);
        MemberUserRespVO referrerUser = getMemberUserRespVO(sharePathDO.getReferrerId());

        // 获取AB区用户的信息
        Map<String, MemberUserRespVO> areaUsers = new HashMap<>();
        MemberUserRespVO AUser = getMemberUserRespVO(sharePathDO.getLeftChildId());
        updateUserAmount(AUser);
        areaUsers.put("A", AUser);
        MemberUserRespVO BUser = getMemberUserRespVO(sharePathDO.getRightChildId());
        updateUserAmount(BUser);
        areaUsers.put("B", BUser);

        PageResult<SharePathDO> shareList = sharePathMapper.selectPage(pageParam, new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getReferrerId, userId));
        List<MemberUserRespVO> list = BeanUtils.toBean(memberUserService.getUserList(shareList.getList().stream().map(SharePathDO::getUserId).collect(Collectors.toList())), MemberUserRespVO.class);
        for (MemberUserRespVO memberUserRespVO : list) {
            updateUserAmount(memberUserRespVO);
        }
        Long referrerCount = sharePathMapper.selectCount(new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getReferrerId, userId));
        PageResult<MemberUserRespVO> result = new PageResult<>(list, referrerCount);
        return AppSharePathRespVO.builder()
//                .parentUser(parentUser)
                .referrerUser(referrerUser)
                .descendants(result)
                .areaUsers(areaUsers)
                .referrerCount(referrerCount)
                .build();
    }

    private void updateUserAmount(MemberUserRespVO user){
        PartitionCrashDO AYesterdayCrash = getYesterdayCrash(user.getId(), 1);
        user.setSurplusAmount(AYesterdayCrash == null ? 0L : AYesterdayCrash.getAfterHitQuota());
        user.setAddAmount(AYesterdayCrash == null ? 0L : AYesterdayCrash.getSonPrice() + AYesterdayCrash.getBrotherPrice());
    }

    /**
     * 获取会员用户信息
     * @param userId 用户id
     * @return 会员用户信息
     */
    private MemberUserRespVO getMemberUserRespVO(Long userId) {
        return BeanUtils.toBean(memberUserService.getUser(userId), MemberUserRespVO.class);
    }

    @Override
    public SharePathDO getSharePathByDescendant(Long userId) {
        List<SharePathDO> sharePathDOS = sharePathMapper.selectList(new LambdaQueryWrapperX<SharePathDO>().eqIfPresent(SharePathDO::getUserId, userId));
        if (sharePathDOS.isEmpty()) {
            return null;
        }
        return sharePathDOS.get(0);
    }

    /**
     * 获取本用户兄弟分区的剩余额度值
     *
     * @param userId 用户编号
     * @return 剩余额度值
     */
    private Long getBrotherSocial(Long userId) {
        PartitionCrashDO yesterdayCrash = getYesterdayCrash(userId, 1);
        return yesterdayCrash == null ? 0 : yesterdayCrash.getBrotherPrice();
    }

    /**
     * 获取昨日分区信息
     *
     * @param userId 用户编号
     * @return 分区信息
     */
    private PartitionCrashDO getYesterdayCrash(Long userId, int today) {
        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT); // 今天的开始时间，即午夜12点
        LocalDateTime localDateTime = todayStart.minusDays(today);
        String yesterdayNo = "CRASH:" + userId + ":" + localDateTime;
        PartitionCrashDO partitionCrashDO = partitionCrashMapper.selectOne(new LambdaQueryWrapperX<PartitionCrashDO>().eqIfPresent(PartitionCrashDO::getPartNo, yesterdayNo));
        List<PartitionCrashDO> partitionCrashDOS = partitionCrashMapper.selectList((new LambdaQueryWrapperX<PartitionCrashDO>()
                .eq(PartitionCrashDO::getUserId, userId))
                .apply("date(create_time) < date(now())")
        );

        //判断这个用户不是第一次碰撞并且没有查询到昨天的碰撞记录,有可能是昨天或者更早定时任务没有启动导致的,所以再往前查几天
        if (!partitionCrashDOS.isEmpty() && partitionCrashDO == null) {
            return getYesterdayCrash(userId, ++today);
        }
        return partitionCrashDO;
    }

    private String getAvatar(Long userId) {
        return memberUserService.getUser(userId).getAvatar();
    }

    @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() {


        return null;
    }

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

    @Override
    public List<Long> sonsId(Long userId) {
        SharePathDO sharePathDOS = sharePathMapper.selectOne(new LambdaQueryWrapperX<SharePathDO>().eq(SharePathDO::getUserId, userId));
        return Arrays.asList(sharePathDOS.getLeftChildId(), sharePathDOS.getRightChildId());

    }


}
