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.bo.InviteMemberBO;
import com.github.wxiaoqi.security.admin.bo.UserBo;
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.mapper.AppUserRelationMapper;
import com.github.wxiaoqi.security.admin.vo.AppUserVo;
import com.github.wxiaoqi.security.admin.vo.InviteMemberVo;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
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.time.Instant;
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;

    @Autowired
    private BranchCompanyBiz companyBiz;


    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
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public   void bindRelation(Integer userId,Integer parentId,Integer companyId,Integer type){
        try {
            if (userId.equals(parentId)){
                log.info("----userId==="+userId+"----parentId===="+parentId+"----自己不能成为自己的上线");
                return;
            }
            if (parentId > 0){
                AppUserVo  appUserVo=userDetailBiz.getUserInfoById(parentId);
                if (appUserVo==null){
                    log.info("----userId==="+userId+"----parentId===="+parentId+"----该上线用户不存在");
                    return;
                }
                AppUserRelation relation=getMyBiz().getRelationByUserId(parentId);
                if(relation==null){
                    relation=new AppUserRelation();
                    relation.setUserId(parentId);
                    relation.setBindType(type);
                    insertSelective(relation);
                }
            }
            Long time=System.currentTimeMillis();
            Long bindTime=time-validTime;
            //判断用户是否有有效的下线
            if (getCountByParentId(userId,bindTime)==0L){
                AppUserRelation  relation=getMyBiz().getRelationByUserId(userId);
                if(relation==null){
                    relation=new AppUserRelation();
                    relation.setUserId(userId);
                    relation.setParentId(parentId);
                    relation.setCompanyId(companyId);
                    relation.setBindType(type);
                    relation.setBindTime(time);
                    insertSelective(relation);
                }else {
                    //判断用户是否有有效的上线
                    Integer parentId1=relation.getParentId() == null ? 0 : relation.getParentId();
                    Integer companyId1=relation.getCompanyId() == null ? 0 : relation.getCompanyId();
                    log.info("----userId==="+userId+"----bindTime===="+bindTime+"----relation.getBindTime()==="+relation.getBindTime());
                    if((parentId1 == 0 && companyId1 == 0)||(relation.getIsForever()!=1&&validTime>0&&relation.getBindTime()<bindTime)){
                        relation.setParentId(parentId);
                        relation.setCompanyId(companyId);
                        relation.setBindType(type);
                        relation.setBindTime(time);
                        getMyBiz().updRelation(relation);
                    }
                }
                if (relation != null && parentId > 0){
                    AppStaffUserDTO staffUserDTO=new AppStaffUserDTO();
                    staffUserDTO.setSuId(relation.getParentId());
                    staffUserDTO.setUid(relation.getUserId());
                    staffUserBiz.addAppStaffUser(staffUserDTO);
                }
            }
        }catch (Exception e){
            log.info("网络异常===" + e.getMessage());
        }

    }

    //首页关系绑定
    public ObjectRestResponse appBindRelation(Integer userId, String code) {
        Integer parentId = 0;
        Integer companyId = 0;
        if (StringUtils.isNotBlank(code)) {
            //判断处理活动关键字
            String[] codes = code.split("_");
            if (codes.length > 1) {
                code = codes[0];
            }
            if (code.contains(CompanyInfoBiz.CODE)){
                companyId=companyBiz.getCompanyByCode(code);
            }else {
                parentId=appUserDetailBiz.getUserByCode(code);
            }
        }
        if (parentId != null && parentId > 0 && userId != null && userId > 0) {
            getMyBiz().bindRelation(userId, parentId, companyId,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,0, 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.getCompanyId() != null && relation.getCompanyId() > 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,0, 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, 0,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());
            }
        }

    }

    public List<UserBo>  findAllRelations(){
        List<UserBo> userBoList = mapper.findAllRelations();
        return CollectionUtils.isEmpty(userBoList)?Collections.emptyList():userBoList;
    }

    public void updateParentIdByUserId(Integer leaderId, Integer userId) {
        mapper.updateParentIdByUserId(leaderId,userId, Instant.now().toEpochMilli());
    }
}

