package com.github.wxiaoqi.security.admin.biz;

import com.ace.cache.annotation.Cache;
import com.ace.cache.annotation.CacheClear;
import com.github.wxiaoqi.security.admin.dto.UserRelationDTO;
import com.github.wxiaoqi.security.admin.entity.*;
import com.github.wxiaoqi.security.admin.feign.dto.AppUserDTO;
import com.github.wxiaoqi.security.admin.vo.AppUserVo;
import com.github.wxiaoqi.security.admin.bo.InviteMemberBO;
import com.github.wxiaoqi.security.admin.vo.InviteMemberVo;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.github.wxiaoqi.security.admin.mapper.AppUserRelationMapper;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户关系表
 *
 * @author libin
 * @email 18178966185@163.com
 * @date 2019-07-03 16:36:44
 */
@Service
@Slf4j
public class AppUserRelationBiz extends BaseBiz<AppUserRelationMapper, AppUserRelation> {

    @Autowired
    AppUserRelationTempBiz relationTempBiz;

    @Autowired
    AppUserDetailBiz userDetailBiz;

    @Autowired
    private AppUserLoginBiz appUserLoginBiz;

    @Value("${temamember.failureTime:60}")
    private Long failureTime;

    @Autowired
    private AppUserDetailBiz appUserDetailBiz;

    @Value("${admin.validTime}")
    private Long validTime;

    @Autowired
    private AppUserPositionTempBiz positionTempBiz;

    @Autowired
    private  AppStaffUserBiz staffUserBiz;

    private static final HashMap<Integer, Boolean> map =  new HashMap<>();
    private static final HashMap<Integer, Boolean> parentMap =  new HashMap<>();
    private static final Object obj = new Object();
    private static final Object parentObj = new Object();

    private boolean lock(Integer userId) {
        synchronized (obj) {
            if (map.get(userId) == null) {
                map.put(userId, true);
                return true;
            }
        }
        return false;
    }
    private boolean parentLock(Integer userId) {
        log.info("---进锁前---parentId===="+userId);
        synchronized (parentObj) {
            log.info("---进锁---parentId===="+userId);
            if (parentMap.get(userId) == null) {
                log.info("---进锁处理---parentId===="+userId);
                parentMap.put(userId, true);
                return true;
            }
        }
        return false;
    }

    private void unParentLock(Integer userId) {
        log.info("---解锁处理---parentId===="+userId);
        synchronized (parentObj) {
            parentMap.remove(userId);
        }
    }

    private void unLock(Integer userId) {
        synchronized (obj) {
            map.remove(userId);
        }
    }

    /**
     * 关系绑定
     * 规则A->B (B无有效上线+无有效下线)
     *
     * @param userId
     * @param parentId
     */
    public   void bindRelation(Integer userId,Integer parentId,Integer type){
        try {
            if (userId.equals(parentId)){
                log.info("----userId==="+userId+"----parentId===="+parentId+"----自己不能成为自己的上线");
                return;
            }

       /* AppUserVo appUserVo=userDetailBiz.getUserInfoById(userId);
        if (appUserVo==null){
            log.info("----userId==="+userId+"----parentId===="+parentId+"----该用户不存在");
            return;
        }*/
            AppUserVo  appUserVo=userDetailBiz.getUserInfoById(parentId);
            if (appUserVo==null){
                log.info("----userId==="+userId+"----parentId===="+parentId+"----该上线用户不存在");
                return;
            }
            if (lock(userId)) {
                AppUserRelation relation = getMyBiz().getRelationByUserId(parentId);
                Long time = System.currentTimeMillis();
                if (relation == null) {
                    insertLock(parentId, type);
                }
                Long bindTime = time - validTime;
                //判断用户是否有有效的下线
                if (getCountByParentId(userId, bindTime) == 0L) {
                    relation = getMyBiz().getRelationByUserId(userId);
                    if (relation == null) {
                        relation = new AppUserRelation();
                        relation.setUserId(userId);
                        relation.setParentId(parentId);
                        relation.setBindType(type);
                        relation.setBindTime(time);
                        insertSelective(relation);
                        AppStaffUserDTO staffUserDTO = new AppStaffUserDTO();
                        staffUserDTO.setSuId(relation.getParentId());
                        staffUserDTO.setUid(relation.getUserId());
                        staffUserBiz.addAppStaffUser(staffUserDTO);
                    } else {
                        //判断用户是否有有效的上线
                        log.info("----userId===" + userId + "----bindTime====" + bindTime + "----relation.getBindTime()===" + relation.getBindTime());
                        if (relation.getParentId() == null || relation.getParentId() == 0 || (relation.getIsForever() != 1 && validTime > 0 && relation.getBindTime() < bindTime)) {
                            relation.setParentId(parentId);
                            relation.setBindType(type);
                            relation.setBindTime(time);
                            getMyBiz().updRelation(relation);
                        }
                    }
                }
            }
        }catch (Exception e){
            log.info("网络异常===" + e.getMessage());
        }finally {
            unLock(userId);
        }

    }

    private void insertLock(Integer userId, Integer type) {
        try {
            if (parentLock(userId)) {
                AppUserRelation relation = getMyBiz().getRelationByUserId(userId);
                if (relation == null) {
                    log.info("insertLock----parentId===" +userId);
                    relation = new AppUserRelation();
                    relation.setUserId(userId);
                    relation.setBindType(type);
                    insertSelective(relation);
                }
            }
        }catch (Exception e){
        }finally {
            unParentLock(userId);
        }
    }

    //首页关系绑定
    public ObjectRestResponse appBindRelation(Integer userId, String code) {
        Integer parentId = 0;
        if (StringUtils.isNotBlank(code)) {
            //判断处理活动关键字
            String[] codes = code.split("_");
            if (codes.length > 1) {
                code = codes[0];
            }
            parentId = appUserDetailBiz.getUserByCode(code);
        }
        if (parentId != null && parentId > 0 && userId != null && userId > 0) {
            getMyBiz().bindRelation(userId, parentId, 1);
        }
        return ObjectRestResponse.succ();
    }

    //后台关系绑定
    public ObjectRestResponse adminBindRelation(UserRelationDTO relationDTO) {
        String phone = relationDTO.getPhone();
        Integer userId = relationDTO.getUserId();
        if (StringUtils.isBlank(phone) || userId == null || userId == 0) {
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数不能为空");
        }
        AppUserLogin userLogin = appUserLoginBiz.checkeUserLogin(phone);
        if (userLogin == null) {
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "该上级不存在");
        }
        Integer parentId = userLogin.getId();
        getMyBiz().bindRelation(userId, parentId, 1);
        return ObjectRestResponse.succ();
    }

    //永久稳定关系
    public void foreverBind(Integer user_id) {
        AppUserRelation relation = getMyBiz().getRelationByUserId(user_id);
        if (relation != null && relation.getIsForever() == 0 && relation.getParentId() != null && relation.getParentId() > 0) {
            relation.setIsForever(1);
            getMyBiz().updRelation(relation);
        }

    }

    /**
     * 小程序分享上下线绑定
     *
     * @param userid          当前人小程序id
     * @param pid             分享人id
     * @param platform_userid 当前人统一平台id
     */
    public ObjectRestResponse shareParentByUserId(Integer userid, Integer pid, Integer platform_userid) {
        if (pid == null || pid == 0 || ((platform_userid == null || platform_userid == 0) && (userid == 0 || userid == null))) {
            return ObjectRestResponse.createFailedResult(ResultCode.NULL_CODE, "参数为空");
        }
        if (platform_userid == null || platform_userid == 0) {
            upRelationTemp(pid, userid);
        } else {
            AppUserVo userVo = userDetailBiz.getUserInfoById(platform_userid);
            if (userVo == null) {
                upRelationTemp(pid, userid);
            } else {
                bindRelation(platform_userid, pid, 2);
            }
        }
        return ObjectRestResponse.succ();

    }

    /**
     * 新增临时关系
     *
     * @param pid
     * @param userid
     */
    public void upRelationTemp(Integer pid, Integer userid) {

        AppUserRelationTemp relationTemp = new AppUserRelationTemp();
        relationTemp.setTempId(userid);
        relationTemp.setIsDel(0);
        relationTemp.setType(1);
        AppUserRelationTemp relationTemp1 = relationTempBiz.selectOne(relationTemp);
        if (relationTemp1 == null) {
            relationTemp.setUserId(pid);
            relationTempBiz.insertSelective(relationTemp);
        }

    }

    /**
     * 小程序上下线绑定
     *
     * @param platform_userid 当前人统一平台id
     * @param userid          当前人小程序id
     */
    public void bindByUserId(Integer platform_userid, Integer userid) {
        if (platform_userid == null || platform_userid == 0 || userid == null || userid == 0) {
            return;
        }
        AppUserRelationTemp relationTemp = new AppUserRelationTemp();
        relationTemp.setTempId(userid);
        relationTemp.setIsValid(0);
        relationTemp.setType(1);
        relationTemp.setIsDel(0);
        relationTemp=relationTempBiz.selectOne(relationTemp);
        if(relationTemp==null){
           return;
        }
        Integer parentId = relationTemp.getUserId();
        bindRelation(platform_userid, parentId, 2);

    }

    /**
     * 获取用户的上线关系
     *
     * @param userId
     * @return
     */
    @Cache(key = "user:relation{1}")
    public AppUserRelation getRelationByUserId(Integer userId) {
       /* AppUserRelation relation = new AppUserRelation();
        relation.setUserId(userId);*/
        Example example=new Example(AppUserRelation.class);
        example.createCriteria().andEqualTo("userId",userId);
        List<AppUserRelation> list=selectByExample(example);
        if (list.size()>0){
            return  list.get(0);
        }
        return null;
    }

    //获取有效的上线
    public AppUserRelation getRelationByIdUserIdAndTime(Integer userId) {
        AppUserRelation userRelation = getMyBiz().getRelationByUserId(userId);
        if (userRelation == null) {
            return null;
        }
        log.info("---userId===" + userId + "-----isForever===" + userRelation.getIsForever());
        if (validTime == null || validTime == 0) {
            return userRelation;
        }
        Long time = System.currentTimeMillis() - validTime;
        if (userRelation.getIsForever() == 1 || userRelation.getBindTime() > time) {
            return userRelation;
        }
        log.info("---userId===" + userId + "-----time===" + time + "----userRelation.getBindTime()===" + userRelation.getBindTime());
        return null;
    }

    //获取用户的下线总数
    public int getCountByParentId(Integer parentId, Long time) {
        if (validTime <= 0) {
            time = validTime;
        }
        return mapper.countByParentId(parentId, time);
    }

    @CacheClear(key = "user:relation{1.userId}")
    public int updRelation(AppUserRelation appUserRelation) {
        return super.updateSelectiveByIdRe(appUserRelation);
    }

    private AppUserRelationBiz getMyBiz() {
        return AopContext.currentProxy() != null ? (AppUserRelationBiz) AopContext.currentProxy() : this;
    }

    public List<AppUserRelation> findMemberPageByLeaderId(Integer leaderId) {
        return mapper.selectByLeaderId(leaderId);
    }

    public InviteMemberVo findInviteMemberByActivitState(Integer leaderId, Integer state, Integer page, Integer limit) {

        InviteMemberVo inviteMemberVo = new InviteMemberVo();
        inviteMemberVo.setPage(page);
        inviteMemberVo.setLimit(limit);
        inviteMemberVo.setFailureTime(failureTime * 24 * 60 * 60);
        Example example = new Example(AppUserRelation.class);
        Example.Criteria criteria = example.createCriteria();
        if (state != null) {
            criteria.andEqualTo("isForever", state);
        }
        criteria.andEqualTo("parentId", leaderId);
        PageDataVO<AppUserRelation> pageDataVO = PageDataVO.pageInfo(page, limit, () -> mapper.selectByExample(example));
        List<AppUserRelation> appUserRelations = pageDataVO.getData();
        if (CollectionUtils.isEmpty(appUserRelations)) {
            inviteMemberVo.setInviteMembers(Collections.EMPTY_LIST);
            return inviteMemberVo;
        }

        List<Integer> memberIds = appUserRelations.stream().map(AppUserRelation::getUserId).collect(Collectors.toList());
        Map<Integer, AppUserLogin> userIdAndUserLoginMap = appUserLoginBiz.findUserIdAndUserLoginMapByMemberIds(memberIds);
        Map<Integer, AppUserDetail> userIdAndUserDetailMap = userDetailBiz.findUserIdAndUserDetailMapByMemberIds(memberIds);

        List<InviteMemberBO> inviteMemberBOS = new ArrayList<>();
        InviteMemberBO inviteMemberBO;
        for (AppUserRelation appUserRelation : appUserRelations) {
            if (userIdAndUserLoginMap == null || userIdAndUserDetailMap == null) {
                continue;
            }
            inviteMemberBO = new InviteMemberBO();
            inviteMemberBO.setUserId(appUserRelation.getUserId());
            inviteMemberBO.setParentId(appUserRelation.getParentId());
            inviteMemberBO.setBindTime(appUserRelation.getBindTime());
            inviteMemberBO.setJoinTime(appUserRelation.getBindTime());
            inviteMemberBO.setUsername(userIdAndUserLoginMap == null ? "" : userIdAndUserLoginMap.get(appUserRelation.getUserId()) == null ? "" : userIdAndUserLoginMap.get(appUserRelation.getUserId()).getUsername());
            inviteMemberBO.setHeadUrl(userIdAndUserDetailMap == null ? "" : userIdAndUserDetailMap.get(appUserRelation.getUserId()) == null ? "" : userIdAndUserDetailMap.get(appUserRelation.getUserId()).getHeadimgurl());
            inviteMemberBOS.add(inviteMemberBO);
        }
        inviteMemberVo.setTotalCount(pageDataVO.getTotalCount().intValue());
        inviteMemberVo.setTotalPage(pageDataVO.getTotalPage());
        inviteMemberVo.setInviteMembers(inviteMemberBOS);
        return inviteMemberVo;
    }

    public Integer findLeaderIdByMemberId(Integer userId) {
        Example example = new Example(AppUserRelation.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId", userId);
        List<AppUserRelation> appUserRelations = mapper.selectByExample(example);
        if (CollectionUtils.isEmpty(appUserRelations)) {
            return 0;
        }
        return appUserRelations.get(0).getParentId();
    }

    public Map<Integer, Integer> findMemberSateAndCountMapByLeaderId(Integer userId) {
        Map<Integer, Integer> memberSateAndCountMap = new HashMap<>();
        List<AppUserRelation> appUserRelationList =  mapper.selectCountByLeaderId(userId);
        if (CollectionUtils.isEmpty(appUserRelationList)){
            memberSateAndCountMap.put(0, 0);
            memberSateAndCountMap.put(1, 0);
        }
        Map<Boolean, Long> resultMap = appUserRelationList.stream().collect(Collectors.partitioningBy(x -> x.getIsForever() == 0, Collectors.counting()));
        memberSateAndCountMap.put(0, resultMap.get(Boolean.TRUE)==null?0:resultMap.get(Boolean.TRUE).intValue());
        memberSateAndCountMap.put(1, resultMap.get(Boolean.FALSE)==null?0:resultMap.get(Boolean.FALSE).intValue());
        return memberSateAndCountMap;
    }

    public void deleteByMemberIds(Collection<Integer> userIds) {
        Example example = new Example(AppUserRelation.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("parentId", userIds);
        List<AppUserRelation> list = mapper.selectByExample(example);
        for (AppUserRelation appUserRelation : list) {
            getMyBiz().delRelation(appUserRelation.getUserId());
        }
        mapper.deleteByExample(example);
        Example example2 = new Example(AppUserRelation.class);
        Example.Criteria criteria1 = example2.createCriteria();
        criteria1.andIn("userId", userIds);
        mapper.deleteByExample(example2);
        for (Integer userId : userIds) {
            getMyBiz().delRelation(userId);
        }
    }

    @CacheClear(key = "user:relation{1}")
    public void delRelation(Integer userId) {

    }


    public List<AppUserRelation> findLeaderByUserIds(List<Integer> userIds) {
        List<AppUserRelation> appUserRelationList = mapper.selectByUserIds(userIds);
        return appUserRelationList == null ? Collections.EMPTY_LIST : appUserRelationList;
    }

    public void initParentId(AppUserDTO userDTO, Integer userid) {
        AppUserRelation relation = getRelationByIdUserIdAndTime(userid);
        Integer parentId = 0;
        if (relation != null) {
            parentId = relation.getParentId();
        }
        userDTO.setParentId(parentId);
        if (parentId != null && parentId > 0) {
            AppUserPositionTemp positionTemp = positionTempBiz.getOne(parentId);
            if (positionTemp != null) {
                userDTO.setParentPositionId(positionTemp.getPositionId());
                userDTO.setParentPositionTempId(positionTemp.getId());
                userDTO.setParentCompanyId(positionTemp.getCompanyId());
            }
        }

    }
}

