package com.lantone.security.facade;

import cn.hutool.crypto.digest.BCrypt;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.lantone.common.api.CommonResult;
import com.lantone.common.constant.AuthConstant;
import com.lantone.common.domain.UserDto;
import com.lantone.security.dto.GetDeptTreeDTO;
import com.lantone.security.dto.GetHospitalTreeDTO;
import com.lantone.security.dto.GetUserDTO;
import com.lantone.security.dto.GetUserHospitalDeptDTO;
import com.lantone.security.dto.GetUserHospitalsDTO;
import com.lantone.security.dto.GetUserPageDTO;
import com.lantone.common.dto.JwtStore;
import com.lantone.common.dto.LoginLogDTO;
import com.lantone.common.dto.SendToTopicDTO;
import com.lantone.security.dto.SoftwareDTO;
import com.lantone.security.dto.UserInfoDTO;
import com.lantone.security.dto.UserRoleDTO;
import com.lantone.security.dto.UserSoftwareHospitalDTO;
import com.lantone.common.enums.DataAuthDataTypeEnum;
import com.lantone.common.enums.IsDeleteEnum;
import com.lantone.common.enums.StatusEnum;
import com.lantone.common.exception.Asserts;
import com.lantone.common.service.RedisService;
import com.lantone.common.service.SysTokenService;
import com.lantone.common.util.DateUtil;
import com.lantone.common.util.EntityUtil;
import com.lantone.common.util.HttpUtils;
import com.lantone.common.util.ListUtil;
import com.lantone.common.util.StringUtil;
import com.lantone.common.util.SysUserUtils;
import com.lantone.security.vo.AddHospitalTreeVO;
import com.lantone.security.vo.AddUserVO;
import com.lantone.security.vo.GetUserPageVO;
import com.lantone.security.vo.LoginVO;
import com.lantone.security.vo.UpdateUserVO;
import com.lantone.security.entity.Dept;
import com.lantone.security.entity.DeptUser;
import com.lantone.security.entity.Doctor;
import com.lantone.security.entity.Hospital;
import com.lantone.security.entity.HospitalUser;
import com.lantone.security.entity.MedoupDoctor;
import com.lantone.security.entity.Role;
import com.lantone.security.entity.User;
import com.lantone.security.entity.UserRole;
import com.lantone.security.facade.base.DeptFacade;
import com.lantone.security.facade.base.DeptUserFacade;
import com.lantone.security.facade.base.DictionaryInfoFacade;
import com.lantone.security.facade.base.DoctorFacade;
import com.lantone.security.facade.base.HospitalFacade;
import com.lantone.security.facade.base.HospitalUserFacade;
import com.lantone.security.facade.base.MedoupDoctorFacade;
import com.lantone.security.facade.base.RoleFacade;
import com.lantone.security.facade.base.UserFacade;
import com.lantone.security.facade.base.UserRoleFacade;
import com.lantone.security.enums.DictionaryEnum;
import com.lantone.security.enums.HospitalTypeEnum;
import com.lantone.security.enums.RelationEnum;
import com.lantone.security.enums.ReturnTypeEnum;
import com.lantone.security.client.AuthService;
import com.lantone.security.client.MessageService;
import eu.bitwalker.useragentutils.UserAgent;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @Description: 用户管理-业务处理类
 * @author: rengb
 * @time: 2021/7/20 12:39
 */
@Component
public class UserManagementFacade {

    @Autowired
    private AuthService authService;
    @Autowired
    private HospitalFacade hospitalFacade;
    @Autowired
    private HospitalUserFacade hospitalUserFacade;
    @Autowired
    private DeptUserFacade deptUserFacade;
    @Autowired
    private DeptFacade deptFacade;
    @Autowired
    private UserFacade userFacade;
    @Autowired
    private DeptUserFacade userDeptFacade;
    @Autowired
    private UserRoleFacade userRoleFacade;
    @Autowired
    private RoleFacade roleFacade;
    @Autowired
    private MedoupDoctorFacade medoupDoctorFacade;
    @Autowired
    private DoctorFacade doctorfacade;
    @Autowired
    private DictionaryInfoFacade dictionaryInfoFacade;
    @Autowired
    private MessageService messageService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private SysTokenService sysTokenService;

    public CommonResult login(LoginVO loginVO) {
        Map<String, String> params = new HashMap<>();
        params.put("client_id", AuthConstant.SECURITY_CENTER_CLIENT_ID);
        params.put("client_secret", "lantone_20210723");
        params.put("grant_type", "password");
        params.put("username", loginVO.getUsername());
        params.put("password", loginVO.getPassword());
        CommonResult restResult = authService.getAccessToken(params);
        userLoginCheck(restResult);
        sendLogRecordMessage(restResult);
        return restResult;
    }

    private void userLoginCheck(CommonResult restResult) {
        if (restResult.getData() != null) {
            Map<String, Object> map = JSONObject.parseObject(JSON.toJSONString(restResult.getData()));
            if (map.containsKey(AuthConstant.ASSESS_TOKEN) && null != map.get(AuthConstant.ASSESS_TOKEN)) {
                String userId = sysTokenService.getUserIDByToken(map.get(AuthConstant.ASSESS_TOKEN).toString());
                JwtStore oldJwt = sysTokenService.getToken(userId);
                String ip = HttpUtils.getIpAddress();
                //异地登录
                if (StringUtil.isNotBlank(ip)
                        && oldJwt != null
                        && !ip.equals(oldJwt.getIp())) {
                    //推送消息
                    List<SendToTopicDTO> sendToTopics = new ArrayList<>();
                    SendToTopicDTO sendToTopicDTO = new SendToTopicDTO();
                    sendToTopicDTO.setMessage("温誓提示，您的账号在其它地方已登录您将被迫下线!");
                    sendToTopicDTO.setType("login");
                    sendToTopicDTO.setTopic(userId);
                    sendToTopics.add(sendToTopicDTO);
                    messageService.sendToTopic(sendToTopics);
                }
                JwtStore jwtStore = new JwtStore();
                jwtStore.setAccessToken(map.get(AuthConstant.ASSESS_TOKEN).toString());
                jwtStore.setRefreshToken(map.get(AuthConstant.REFRESH_TOKEN).toString());
                jwtStore.setIp(HttpUtils.getIpAddress());
                sysTokenService.createToken(jwtStore);
            }
        }
    }

    public UserDto loadUserByUsername(String username) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username", username);
        userQueryWrapper.eq("is_deleted", IsDeleteEnum.N.getKey());
        List<User> userList = userFacade.list(userQueryWrapper);
        if (userList.size() == 0) {
            CommonResult.failed("用户不存在！");
//            Asserts.fail("用户不存在！");
        }
        if (userList.size() > 1) {
            CommonResult.failed("当前账号异常！");
//            Asserts.fail("当前账号异常！");
        }

        UserDto userDTO = new UserDto();
        User user = userList.get(0);
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("is_deleted", IsDeleteEnum.N.getKey());
        userRoleQueryWrapper.eq("user_id", user.getId());
        List<Long> roleIdList = userRoleFacade.list(userRoleQueryWrapper)
                .stream()
                .map(i -> i.getRoleId())
                .collect(Collectors.toList());

        QueryWrapper<Role> roleQueryWrapper = new QueryWrapper<>();
        roleQueryWrapper.eq("is_deleted", IsDeleteEnum.N.getKey());
        roleQueryWrapper.eq("status", StatusEnum.Enable.getKey());
        roleQueryWrapper.in(ListUtil.isNotEmpty(roleIdList), "id", roleIdList);
        List<String> roleIdNames = roleFacade.list(roleQueryWrapper).stream().map(i -> i.getId() + "_" + i.getName()).collect(Collectors.toList());

        BeanUtils.copyProperties(user, userDTO);
        userDTO.setUserName(user.getUsername());
        userDTO.setRoles(roleIdNames);
        return userDTO;
    }

    /**
     * @param addUserVO
     * @Description添加用户
     * @Return boolean
     */
    public boolean addUser(AddUserVO addUserVO) {
        //1.新增用户基本信息
        User user = new User();
        BeanUtils.copyProperties(addUserVO, user);
        user.setCreator(SysUserUtils.getCurrentPrincipleId() + "");
        user.setGmtCreate(DateUtil.now());
        user.setPassword(BCrypt.hashpw(user.getPassword()));
        //1.1校验用户
        boolean deptFlag = false;
        if (ListUtil.isNotEmpty(addUserVO.getAddHospitalTreeVO().getDepts())) {
            deptFlag = true;
        }
        checkUser(user, deptFlag, addUserVO.getAddHospitalTreeVO().getHospitals(), addUserVO.getRoles());
        try {
            if (userFacade.save(user)) {
                //2.插入用户所属组织
                return saveUserHospital(addUserVO.getAddHospitalTreeVO(), user.getId(), addUserVO.getRoles());
            } else {
                Asserts.fail("用户添加失败");
            }
        } catch (Exception e) {
            Asserts.fail("用户添加失败");
        }
        return false;
    }

    /**
     * @param user
     * @param hospitals 插入用户组织id
     * @param roles     插入用户角色id
     * @Description用户校验
     * @Return void
     */
    private void checkUser(User user, boolean deptFlag, List<Long> hospitals, List<Long> roles) {

        //1.当前登录用户、组织是否还存在、能用
        loginCheck();
        //2.当前用户是否已存在
        //添加时判断
        List<User> users = userFacade.list(new QueryWrapper<User>()
                .eq("username", user.getUsername()));
        if (user.getId() == null) {
            if (ListUtil.isNotEmpty(users)) {
                Asserts.fail("该用户已存在,请更换用户名");
            }
            //修改时判断
        } else {
            if (ListUtil.isNotEmpty(users)) {
                users.stream().forEach(user1 -> {
                    if (!user.getId().equals(user1.getId())) {
                        Asserts.fail("该用户已存在,请更换用户名");
                    }
                });
            }
        }
        //3.校验插入用户所属组织是否正常
        checkHospitals(hospitals);
        //4.校验插入用户角色是否正常
        //        checkRoles(roles);(目前角色校验有问题通过id查不到角色）
        //5.用户如果没有医疗组、科室 绑定角色不能选择本医疗组、全部科室除本科室外、本科室数据权限角色
        //科室
        userDeptCheck(roles, deptFlag);
        //医疗组(无医生信息，就不会有医疗组；有医生信息无医疗组）
        boolean groupFlag = false;
        if (StringUtil.isEmpty(user.getJobNo())) {
            groupFlag = true;
        } else {
            List<Doctor> doctors = doctorfacade.list(new QueryWrapper<Doctor>()
                    .eq("code", user.getJobNo())
                    .eq("is_deleted", IsDeleteEnum.N.getKey()));
            if (ListUtil.isNotEmpty(doctors)) {
                List<MedoupDoctor> medoupDoctors = medoupDoctorFacade.list(new QueryWrapper<MedoupDoctor>()
                        .in("dcotor_id", doctors.stream().map(Doctor::getId).collect(Collectors.toList()))
                        .eq("is_deleted", IsDeleteEnum.N.getKey()));
                if (ListUtil.isEmpty(medoupDoctors)) {
                    groupFlag = true;
                }
            }
        }
        if (!groupFlag) {
            usermedoupCheck();
        }
    }

    /**
     * @param
     * @Description医疗组校验
     * @Return void
     */
    private void usermedoupCheck() {

        //获取当前用户的角色
        List<Long> dataTypes = new ArrayList<>();
        dataTypes.add(DataAuthDataTypeEnum.SELF_MEDOUP.getKey() * 1l);
        List<UserRoleDTO> checkRoles = roleFacade.getBaseMapper()
                .getDataAuthRole(SysUserUtils.getCurrentPrincipleId(), null, dataTypes);
        StringBuffer errStr = new StringBuffer();
        if (ListUtil.isNotEmpty(checkRoles)) {
            checkRoles.stream().forEach(userRoleDTO -> {
                errStr.append(userRoleDTO.getRoleName() + ";");
            });
            Asserts.fail(errStr.toString() + "角色需要用户填写医生工号并且该医生存在医疗组信息");
        }
    }

    /**
     * @param roles
     * @Description校验用户如果没有科室信息时，是否分配科室数据权限相关的角色
     * @Return void
     */
    private void userDeptCheck(List<Long> roles, boolean deptFlag) {
        //获取当前用户的角色
        List<Long> dataTypes = new ArrayList<>();
        dataTypes.add(DataAuthDataTypeEnum.ALL_DEPT_NOT_SELF.getKey() * 1l);
        dataTypes.add(DataAuthDataTypeEnum.ALL_SELF_DEPT.getKey() * 1l);
        List<UserRoleDTO> checkRoles = roleFacade.getBaseMapper()
                .getDataAuthRole(SysUserUtils.getCurrentPrincipleId(), roles, dataTypes);
        StringBuffer errStr = new StringBuffer();
        //角色需要用户包含科室信息
        if (ListUtil.isNotEmpty(checkRoles)) {
            if (!deptFlag) {
                checkRoles.stream().forEach(userRoleDTO -> {
                    errStr.append(userRoleDTO.getRoleName() + ";");
                });
            }
            if (StringUtil.isNotEmpty(errStr.toString())) {
                Asserts.fail(errStr.toString() + "角色需要用户具备科室信息");
            }
        }
    }

    /**
     * 修改密码
     *
     * @param password       原密码
     * @param modifyPassword 新密码
     * @return 修改密码是否成功
     */
    public Boolean modifyPassword(String password, String modifyPassword) {
        //使用MD5对原密码和新密码进行加密
        String MD5Password = BCrypt.hashpw(password);
        String MD5ModifyPassword = BCrypt.hashpw(modifyPassword);
        //对传入的密码进行格式验证
        Long hospitalID = SysUserUtils.getCurrentHospitalId();
        Boolean regularBoolean = passwordRegular(modifyPassword, hospitalID + "");
        if (!regularBoolean) {
            Asserts.fail("请输入正确格式的新密码");
        }
        String userId = SysUserUtils.getCurrentPrincipleId() + "";
        User user = userFacade.getOne(new QueryWrapper<User>()
                .eq("is_deleted", IsDeleteEnum.N.getKey())
                .eq("status", StatusEnum.Enable.getKey())
                .eq("id", userId), false);
        if (null == user) {
            Asserts.fail("用户不存在");
        }

        if (!BCrypt.checkpw(password, user.getPassword())) {
            Asserts.fail("原密码错误");
        }
        if (password.equals(modifyPassword)) {
            Asserts.fail("原密码和新密码不能相同");
        }
        user.setPassword(MD5ModifyPassword);
        user.setGmtModified(DateUtil.now());
        user.setModifier(userId);
        return userFacade.updateById(user);
    }


    /**
     * 未加密密文正则表达式  至少8个字符，1个大写字母，1个小写字母，1个数字和1个特殊字符：
     *
     * @param password
     * @return
     */
    public Boolean passwordRegular(String password, String hospitalId) {
        boolean check = true;
        Map<String, Map<String, String>> dictionaryWithKey = dictionaryInfoFacade.getDicMap(ReturnTypeEnum.INTERFACE.getKey(),
                Lists.newArrayList(DictionaryEnum.PASSWORD.getKey() + ""));
        if (dictionaryWithKey != null) {
            Map<String, String> stringStringMap = dictionaryWithKey.get(DictionaryEnum.PASSWORD.getKey() + "");
            if (stringStringMap != null) {
                String regular = stringStringMap.get("check");
                if (StringUtil.isNotEmpty(regular)) {
                    check = password.matches(regular);
                }
            }
        }
        return check;
    }

    /**
     * @param roles
     * @Description插入角色校验
     * @Return void
     */
    private void checkRoles(List<Long> roles) {
        if (ListUtil.isNotEmpty(roles)) {
            if (roles.size() != roleFacade.getBaseMapper().getCount(roles, StatusEnum.Enable.getKey(), IsDeleteEnum.N.getKey())) {
                Asserts.fail("插入用户角色列表有改动,请刷新页面重新操作");
            }
        }
    }

    /**
     * @param hospitals
     * @Description插入组织校验
     * @Return void
     */
    private void checkHospitals(List<Long> hospitals) {
        if (ListUtil.isNotEmpty(hospitals)) {
            if (hospitals.size() != hospitalFacade.list(new QueryWrapper<Hospital>()
                    .in("id", hospitals)
                    .eq("status", StatusEnum.Enable.getKey())
                    .eq("is_deleted", IsDeleteEnum.N.getKey())).size()) {
                Asserts.fail("插入用户所属组织有改动,请刷新页面重新操作");
            }
        }
    }

    /**
     * @param
     * @Description操作用户校验
     * @Return void
     */
    private void loginCheck() {
        if (hospitalFacade.list(new QueryWrapper<Hospital>()
                .eq("id", SysUserUtils.getCurrentHospitalId())
                .eq("status", StatusEnum.Enable.getKey())
                .eq("is_deleted", IsDeleteEnum.N.getKey())).size() <= 0) {
            Asserts.fail("操作用户所属组织已被禁用或删除");
        }
        if (userFacade.list(new QueryWrapper<User>()
                .eq("id", SysUserUtils.getCurrentPrincipleId())
                .eq("status", StatusEnum.Enable.getKey())
                .eq("is_deleted", IsDeleteEnum.N.getKey())).size() <= 0) {
            Asserts.fail("该账号暂未开通或已被禁用，请联系管理员~");
        }
    }

    /**
     * @param addHospitalTreeVO
     * @param userId
     * @Description保存用户关联的医院、科室
     * @Return boolean
     */
    private boolean saveUserHospital(AddHospitalTreeVO addHospitalTreeVO, Long userId, List<Long> roles) {

        if (ListUtil.isEmpty(addHospitalTreeVO.getDepts()) && ListUtil.isEmpty(addHospitalTreeVO.getHospitals())) {
            Asserts.fail("用户关联的医院或科室都为空");
        }
        //如果选择科室没有添加科室对应的医院
        if (ListUtil.isNotEmpty(addHospitalTreeVO.getDepts())) {
            addHospitalTreeVO.getHospitals().addAll(deptFacade.list(new QueryWrapper<Dept>()
                    .in("id", addHospitalTreeVO.getDepts())
                    .eq("is_deleted", IsDeleteEnum.N.getKey())
                    .eq("status", StatusEnum.Enable.getKey())).stream().map(Dept::getHospitalId).collect(Collectors.toList()));
            //去重
            Set<Long> hospitalSet = new HashSet<>(addHospitalTreeVO.getHospitals());
            List<Long> hospitals = new ArrayList<>(hospitalSet);
            addHospitalTreeVO.setHospitals(hospitals);
        }

        //插入用户和科室的关系（没有科室信息默认为全院）
        if (ListUtil.isNotEmpty(addHospitalTreeVO.getDepts())) {
            addHospitalTreeVO.getDepts().stream().forEach(deptID -> {
                DeptUser userDept = new DeptUser();
                userDept.setDeptId(deptID);
                userDept.setUserId(userId);
                userDeptFacade.save(userDept);
            });
        }
        //插入用户和医院的关系
        if (ListUtil.isNotEmpty(addHospitalTreeVO.getHospitals())) {
            addHospitalTreeVO.getHospitals().stream().forEach(hospitalId -> {
                HospitalUser hospitalUser = new HospitalUser();
                hospitalUser.setUserId(userId);
                hospitalUser.setHospitalId(hospitalId);
                hospitalUserFacade.save(hospitalUser);
            });
        }
        //插入用户和角色的关系
        return saveUserRole(userId, roles);
    }

    /**
     * @param userId
     * @param roles
     * @Description插入用户和角色的关系
     * @Return boolean
     */
    private boolean saveUserRole(Long userId, List<Long> roles) {
        if (ListUtil.isNotEmpty(roles)) {
            roles.stream().forEach(roleId -> {
                UserRole userRole = new UserRole();
                userRole.setRoleId(roleId);
                userRole.setUserId(userId);
                userRoleFacade.save(userRole);
            });
            return true;
        }
        return false;
    }

    /**
     * @param
     * @Description获取当前用户的组织机构树
     * @Return java.util.List<com.lantone.security.dto.GetHospitalTreeDTO>
     */
    public List<GetHospitalTreeDTO> getLoginUserHospitalTree() {
        Hospital hospital = hospitalFacade.getById(SysUserUtils.getCurrentHospitalId());
        if (hospital == null) {
            Asserts.fail("登录用户组织不存在,请联系管理员~");
        }
        //获取当前医院的树状结构
        List<GetHospitalTreeDTO> hospitalTrees = hospitalFacade.getBaseMapper()
                .getHospitalTreeInfo(SysUserUtils.getCurrentHospitalId(), StatusEnum.Enable.getKey());
        //根据parentid分组
        Map<Long, List<GetHospitalTreeDTO>> hospitalMap = EntityUtil.makeEntityListMap(hospitalTrees, "parentId");
        //深度遍历拼装结果
        List<GetHospitalTreeDTO> hospitalTree = hospitalMap.get(hospital.getParentId());
        for (GetHospitalTreeDTO getHospitalTreeDTO : hospitalTree) {
            //真实医院添加科室信息
            if (HospitalTypeEnum.SINGLE_HOSPITAL.getKey() == Integer.parseInt(getHospitalTreeDTO.getType())) {
                getHospitalTreeDTO.setDepts(deptFacade.getBaseMapper().getDeptInfo(getHospitalTreeDTO.getHospitalId()));
            }
            getSonHospital(getHospitalTreeDTO, hospitalMap);
        }
        return hospitalTree;
    }


    /**
     * @param updateUserVO
     * @Description修改用户
     * @Return boolean
     */
    public boolean updateUser(UpdateUserVO updateUserVO) {
        //1.删除该用户关联的科室、医院
        if (delUserHospitalORDept(updateUserVO.getId())) {
            User user = new User();
            BeanUtils.copyProperties(updateUserVO, user);
            user.setPassword(BCrypt.hashpw(user.getPassword()));
            //1.1校验用户
            boolean deptFlag = false;
            if (ListUtil.isNotEmpty(updateUserVO.getAddHospitalTreeVO().getDepts())) {
                deptFlag = true;
            }
            checkUser(user, deptFlag, updateUserVO.getAddHospitalTreeVO().getHospitals(), updateUserVO.getRoles());
            //修改用户不修改密码
            user.setPassword(null);
            if (userFacade.updateById(user)) {
                //2.插入用户新关联的医院、科室
                return saveUserHospital(updateUserVO.getAddHospitalTreeVO(), updateUserVO.getId(), updateUserVO.getRoles());
            } else {
                Asserts.fail("用户基本信息修改失败");
            }
        }
        return false;
    }

    /**
     * @param id
     * @Description删除用户与医院、科室的关联关系
     * @Return boolean
     */
    private boolean delUserHospitalORDept(Long id) {
        if (hospitalUserFacade.remove(new UpdateWrapper<HospitalUser>()
                .eq("user_id", id)
                .eq("is_deleted", IsDeleteEnum.N.getKey()))) {
            if (userRoleFacade.remove(new UpdateWrapper<UserRole>()
                    .eq("user_id", id)
                    .eq("is_deleted", IsDeleteEnum.N.getKey()))) {
                if (userDeptFacade.list(new QueryWrapper<DeptUser>()
                        .eq("user_id", id)
                        .eq("is_deleted", IsDeleteEnum.N.getKey())).size() > 0) {
                    return userDeptFacade.remove(new UpdateWrapper<DeptUser>()
                            .eq("user_id", id)
                            .eq("is_deleted", IsDeleteEnum.N.getKey()));
                }
                return true;
            } else {
                Asserts.fail("用户和角色的关联关系删除失败");
            }
        } else {
            Asserts.fail("用户和医院的关联关系删除失败");
        }
        return false;
    }

    /**
     * @param userId
     * @Description删除用户
     * @Return boolean
     */
    public boolean deleteUser(Long userId) {
        return userFacade.update(new UpdateWrapper<User>()
                .set("is_deleted", IsDeleteEnum.Y.getKey())
                .eq("id", userId));
    }

    /**
     * @param userId
     * @param status
     * @Description启用禁用用户
     * @Return boolean
     */
    public boolean disableUser(Long userId, String status) {

        return userFacade.update(new UpdateWrapper<User>()
                .set("status", status)
                .eq("id", userId)
                .eq("is_deleted", IsDeleteEnum.N.getKey()));
    }

    /**
     * @param userId
     * @Description获取用户详情
     * @Return com.lantone.security.dto.GetUserDTO
     */
    public GetUserDTO getUserById(Long userId) {
        GetUserDTO getUserDTO = new GetUserDTO();
        //1.获取用户的基本信息
        User user = userFacade.getById(userId);
        if (user == null) {
            Asserts.fail("该用户不存在请刷新重试~");
        }
        BeanUtils.copyProperties(user, getUserDTO);
        //2.获取当前用户的组织类型
        Hospital hospital = hospitalFacade.getById(SysUserUtils.getCurrentHospitalId());
        if (hospital == null) {
            Asserts.fail("该用户所属组织不存在请刷新重试~");
        }
        //3.获取查询用户的科室id列表、医院id列表
        List<Long> hospitals = hospitalUserFacade.list(new QueryWrapper<HospitalUser>()
                .eq("user_id", userId)
                .eq("is_deleted", IsDeleteEnum.N.getKey())).stream().map(HospitalUser::getHospitalId).collect(Collectors.toList());
        //如果用户属于某医院但是没有科室信息默认为全院
        List<GetUserHospitalDeptDTO> userHospitalDepts = hospitalUserFacade.getBaseMapper().getUserHospitaDeptById(userId);
        //3.2获取当前登录用户的组织机构树
        //获取当前医院的树状结构
        List<GetHospitalTreeDTO> hospitalTrees = hospitalFacade.getBaseMapper()
                .getHospitalTreeInfo(SysUserUtils.getCurrentHospitalId(), StatusEnum.Enable.getKey());
        //根据parentid分组
        Map<Long, List<GetHospitalTreeDTO>> hospitalMap = EntityUtil.makeEntityListMap(hospitalTrees, "parentId");
        //深度遍历拼装结果
        List<GetHospitalTreeDTO> hospitalTree = hospitalMap.get(hospital.getParentId());
        getHospitalDeptInfo(hospitalMap, hospitals, userHospitalDepts, hospitalTree);
        getUserDTO.setHospitals(hospitalTree);

        //4.获取用户的角色
        getUserDTO.setRoles(userRoleFacade.getBaseMapper().getUserRoles(userId));
        return getUserDTO;
    }


    /**
     * 递归获取医院结构
     *
     * @param hospital    当前医院
     * @param hospitalMap 医院集
     */
    public void getSonHospital(GetHospitalTreeDTO hospital, Map<Long, List<GetHospitalTreeDTO>> hospitalMap, List<Long> hospitals, List<GetUserHospitalDeptDTO> userHospitalDepts) {
        List<GetHospitalTreeDTO> hospitalTreeDTOS = hospitalMap.get(hospital.getHospitalId());
        if (ListUtil.isNotEmpty(hospitalTreeDTOS)) {
            hospital.setChildren(hospitalTreeDTOS);
            getHospitalDeptInfo(hospitalMap, hospitals, userHospitalDepts, hospitalTreeDTOS);
        }
    }

    /**
     * @param hospitalMap       医院结果级
     * @param hospitals         查询用户所在医院集
     * @param userHospitalDepts 查询用户所在科室集
     * @param hospitalTreeDTOS  当前遍历医院集
     * @Description
     * @Return void
     */
    private void getHospitalDeptInfo(Map<Long, List<GetHospitalTreeDTO>> hospitalMap, List<Long> hospitals, List<GetUserHospitalDeptDTO> userHospitalDepts, List<GetHospitalTreeDTO> hospitalTreeDTOS) {

        for (GetHospitalTreeDTO bean : hospitalTreeDTOS) {
            //真实医院添加科室信息
            if (HospitalTypeEnum.SINGLE_HOSPITAL.getKey() == Integer.parseInt(bean.getType())) {
                List<GetDeptTreeDTO> getDeptTreeDTOList = deptFacade.getBaseMapper().getDeptInfo(bean.getHospitalId());
                //通过查询用户所在的科室集添加关联关系
                List<Long> depts = userHospitalDepts.stream().map(GetUserHospitalDeptDTO::getDeptId).collect(Collectors.toList());
                List<Long> dHospitals = userHospitalDepts.stream().map(GetUserHospitalDeptDTO::getHospitalId).collect(Collectors.toList());
                getDeptTreeDTOList.stream().forEach(getDeptTreeDTO -> {
                    if (depts.contains(getDeptTreeDTO.getDeptId())) {
                        getDeptTreeDTO.setRelation(RelationEnum.Y.getName());
                        //如果只有医院没有科室则是医院全选
                    } else if (hospitals.contains(bean.getHospitalId()) && !dHospitals.contains(bean.getHospitalId())) {
                        getDeptTreeDTO.setRelation(RelationEnum.Y.getName());
                        bean.setRelation(RelationEnum.Y.getName());
                    }
                });
                bean.setDepts(getDeptTreeDTOList);
            }
            getSonHospital(bean, hospitalMap, hospitals, userHospitalDepts);
        }
    }

    /**
     * 递归获取医院结构
     *
     * @param hospital    当前医院
     * @param hospitalMap 医院集
     * @return 空
     */
    public void getSonHospital(GetUserHospitalsDTO hospital, Map<Long, List<GetUserHospitalsDTO>> hospitalMap) {
        List<GetUserHospitalsDTO> hospitals = hospitalMap.get(hospital.getHospitalId());
        if (ListUtil.isNotEmpty(hospitals)) {
            hospital.setChildren(hospitals);
            for (GetUserHospitalsDTO bean : hospitals) {
                getSonHospital(bean, hospitalMap);
            }
        }
    }

    /**
     * 递归获取医院结构
     *
     * @param hospital    当前医院
     * @param hospitalMap 医院集
     * @return 空
     */
    public void getSonHospital(GetHospitalTreeDTO hospital, Map<Long, List<GetHospitalTreeDTO>> hospitalMap) {
        List<GetHospitalTreeDTO> hospitals = hospitalMap.get(hospital.getHospitalId());
        if (ListUtil.isNotEmpty(hospitals)) {
            hospital.setChildren(hospitals);
            for (GetHospitalTreeDTO bean : hospitals) {
                //真实医院添加科室信息
                if (HospitalTypeEnum.SINGLE_HOSPITAL.getKey() == Integer.parseInt(bean.getType())) {
                    bean.setDepts(deptFacade.getBaseMapper().getDeptInfo(bean.getHospitalId()));
                }
                getSonHospital(bean, hospitalMap);
            }
        }
    }

    /**
     * @param getUserPageVO
     * @Description获取登录用户的用户列表
     * @Return com.baomidou.mybatisplus.core.metadata.IPage<com.lantone.security.dto.GetUserPageDTO>
     */
    public IPage<GetUserPageDTO> getUserPage(GetUserPageVO getUserPageVO) {

        getUserPageVO.setHospitalId(SysUserUtils.getCurrentHospitalId());
        //查出的用户列表不能包含当前登录的管理用户
        getUserPageVO.setLocalUserID(SysUserUtils.getCurrentPrincipleId());
        return hospitalUserFacade.getBaseMapper().getUserPage(getUserPageVO);
    }

    /**
     * @param
     * @Description获取用户所属组织
     * @Return java.util.List<com.lantone.security.dto.GetHospitalTreeDTO>
     */
    public Map<String, Object> getUserHospitals() {
        Map<String, Object> out = new HashMap<>();
        //但系统单家医院直接跳转
        boolean jumpFlag = true;
        //1.获取用户系统信息
        List<SoftwareDTO> softwares = userFacade.getBaseMapper().getUserSoftwareByUId(SysUserUtils.getCurrentPrincipleId());
        if (softwares.size() > 1) {
            jumpFlag = false;
        }
        AtomicInteger count = new AtomicInteger();
        List<UserSoftwareHospitalDTO> userSoftwareHospitals = new ArrayList<>();
        if (ListUtil.isNotEmpty(softwares)) {
            softwares.stream().forEach(softwareDTO -> {
                UserSoftwareHospitalDTO tempU = new UserSoftwareHospitalDTO();
                BeanUtils.copyProperties(softwareDTO, tempU);
                //获取该系统下的医院
                List<GetUserHospitalsDTO> softwareHospitals = userFacade.getBaseMapper()
                        .getUserSoftwareHospitals(SysUserUtils.getCurrentPrincipleId(), softwareDTO.getId());
                count.set(count.get() + softwareHospitals.size());
                //转换成树状结构
                Map<Long, List<GetUserHospitalsDTO>> softwareHospitalMap = EntityUtil.makeEntityListMap(softwareHospitals, "parentId");
                tempU.setHospitals(transTreeData(softwareHospitalMap, softwareHospitals));
                userSoftwareHospitals.add(tempU);
            });
        }
        if (count.get() > 1) {
            jumpFlag = false;
        }
        out.put("jump", jumpFlag);
        out.put("software", userSoftwareHospitals);
        UserInfoDTO userInfo = new UserInfoDTO();
        User user = userFacade.getById(SysUserUtils.getCurrentPrincipleId());
        if (user == null) {
            Asserts.fail("用户不存在，请联系管理员~");
        }
        BeanUtils.copyProperties(user, userInfo);
        out.put("userInfo", userInfo);
        return out;
    }

    /**
     * @param softwareHospitalMap
     * @param softwareHospitals
     * @Description将医院信息转换成树状结构
     * @Return java.util.List<com.lantone.security.dto.GetUserHospitalsDTO>
     */
    private List<GetUserHospitalsDTO> transTreeData(Map<Long, List<GetUserHospitalsDTO>> softwareHospitalMap, List<GetUserHospitalsDTO> softwareHospitals) {
        if (softwareHospitalMap == null) {
            return null;
        }
        List<GetUserHospitalsDTO> out = new ArrayList<>();
        Set<Long> tempParents = new HashSet<>();
        Set<Long> parents = softwareHospitalMap.keySet();
        parents.stream().forEach(id -> {
            softwareHospitals.stream().forEach(getUserHospitalsDTO -> {
                if (getUserHospitalsDTO.getHospitalId().equals(id)) {
                    tempParents.add(id);
                }
            });
        });
        parents.stream().forEach(parentId -> {
            if (!tempParents.contains(parentId)) {
                List<GetUserHospitalsDTO> hospitalListInfos = softwareHospitalMap.get(parentId);
                for (GetUserHospitalsDTO bean : hospitalListInfos) {
                    getSonHospital(bean, softwareHospitalMap);
                }
                out.addAll(hospitalListInfos);
            }
        });
        return out;
    }

    /**
     * @Description: 用户获取token后发送登录信息
     * @Param: [commonResult]
     * @return: void
     * @Author: cy
     * @Date: 2021/9/5
     */
    public void sendLogRecordMessage(CommonResult commonResult) {
        Object data = commonResult.getData();
        if (null != data) {
            Map<String, Object> map = JSONObject.parseObject(JSON.toJSONString(data));
            if (map.containsKey("token") && null != map.get("token")) {
                LoginLogDTO loginLog = new LoginLogDTO();
                Date date = new Date();
                loginLog.setLoginDate(date);
                loginLog.setGmtCreate(date);
                String token = map.get("token").toString();
                UserDto userByToken = SysUserUtils.getUserByToken(token);
                loginLog.setLoginId(userByToken.getId());
                loginLog.setLoginName(userByToken.getUserName());
                loginLog.setLoginIp(HttpUtils.getIpAddress());
                UserAgent userAgent = UserAgent.parseUserAgentString(HttpUtils.getHttpServletRequest().getHeader("User-Agent"));
                // 获取客户端浏览器
                String browser = userAgent.getBrowser().getName();
                loginLog.setLoginBrowser(browser);
                messageService.loginLogHandle(loginLog);
            }
        }
    }

    /**
     *@Description用户登出
     *
     * @param userId
     * @Return com.lantone.common.api.CommonResult<java.lang.Boolean>
     */
    public CommonResult<Boolean> close(String userId) {
        return CommonResult.success(sysTokenService.deleteToken(userId));
    }
}