package com.elephant.framework.galaxy.aroad.module.system.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.elephant.framework.galaxy.aroad.module.attendance.dto.MemberDto;
import com.elephant.framework.galaxy.aroad.module.common.datascope.DataScope;
import com.elephant.framework.galaxy.aroad.module.system.dto.UserDTO;
import com.elephant.framework.galaxy.aroad.module.system.dto.UserInfo;
import com.elephant.framework.galaxy.aroad.module.system.entity.*;
import com.elephant.framework.galaxy.aroad.module.system.mapper.UserMapper;
import com.elephant.framework.galaxy.aroad.module.system.service.*;
import com.elephant.framework.galaxy.aroad.module.system.vo.MenuVO;
import com.elephant.framework.galaxy.aroad.module.system.vo.UserVO;
import com.elephant.framework.galaxy.aroad.util.SecurityUtils;
import com.elephant.framework.galaxy.aroad.constant.CommonConstants;
import com.elephant.framework.galaxy.aroad.module.system.entity.*;
import com.elephant.framework.galaxy.aroad.module.system.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.elephant.framework.galaxy.aroad.response.R;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author wangjian
 * @since 2019-02-21
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
    private final DeptService deptService;
    private final RoleService roleService;
    private final MenuService menuService;
    private final UserRoleService userRoleService;
    private final DeptRelationService deptRelationService;


    /**
     * 保存用户信息
     *
     * @param userDto DTO 对象
     * @return success/fail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(UserDTO userDto) {
        User sysUser = new User();
        BeanUtils.copyProperties(userDto, sysUser);
        sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
        sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
        baseMapper.insert(sysUser);
        List<UserRole> userRoleList = userDto.getRole()
                .stream().map(roleId -> {
                    UserRole userRole = new UserRole();
                    userRole.setUserId(sysUser.getUserId());
                    userRole.setRoleId(roleId);
                    return userRole;
                }).collect(Collectors.toList());
        return userRoleService.saveBatch(userRoleList);
    }

    /**
     * 通过查用户的全部信息
     *
     * @param user 用户
     * @return
     */
    @Override
    public UserInfo findUserInfo(User user) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUser(user);
        //设置角色列表  （ID）
        List<Integer> roleIds = roleService.findRolesByUserId(user.getUserId())
                .stream()
                .map(Role::getRoleId)
                .collect(Collectors.toList());
        userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class));

        //设置权限列表（menu.permission）
        Set<String> permissions = new HashSet<>();
        roleIds.forEach(roleId -> {
            List<String> permissionList = menuService.findMenuByRoleId(roleId)
                    .stream()
                    .filter(menuVo -> StringUtils.isNotEmpty(menuVo.getPermission()))
                    .map(MenuVO::getPermission)
                    .collect(Collectors.toList());
            permissions.addAll(permissionList);
        });
        userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
        return userInfo;
    }

    /**
     * 分页查询用户信息（含有角色信息）
     *
     * @param page    分页对象
     * @param userDTO 参数列表
     * @return
     */
    @Override
    public IPage getUsersWithRolePage(Page page, UserDTO userDTO) {
        return baseMapper.getUserVosPage(page, userDTO, new DataScope());
    }

    /**
     * 通过ID查询用户信息
     *
     * @param id 用户ID
     * @return 用户信息
     */
    @Override
    public UserVO selectUserVoById(Integer id) {
        return baseMapper.getUserVoById(id);
    }

    /**
     * 删除用户
     *
     * @param sysUser 用户
     * @return Boolean
     */
    @Override
    @CacheEvict(value = "user_details", key = "#sysUser.username")
    public Boolean deleteUserById(User sysUser) {
        userRoleService.deleteByUserId(sysUser.getUserId());
        this.removeById(sysUser.getUserId());
        return Boolean.TRUE;
    }

    @Override
    @CacheEvict(value = "user_details", key = "#userDto.username")
    public R updateUserInfo(UserDTO userDto) {
        UserVO userVO = baseMapper.getUserVoByUsername(userDto.getUsername());
        User sysUser = new User();
        if (StrUtil.isNotBlank(userDto.getPassword())
                && StrUtil.isNotBlank(userDto.getNewpassword1())) {
            if (ENCODER.matches(userDto.getPassword(), userVO.getPassword())) {
                sysUser.setPassword(ENCODER.encode(userDto.getNewpassword1()));
            } else {
                log.warn("原密码错误，修改密码失败:{}", userDto.getUsername());
                return new R("fail", "原密码错误，修改失败");
            }
        }
        sysUser.setPhone(userDto.getPhone());
        sysUser.setUserId(userVO.getUserId());
        sysUser.setAvatar(userDto.getAvatar());
        return new R(this.updateById(sysUser));
    }

    @Override
    @CacheEvict(value = "user_details", key = "#userDto.username")
    public Boolean updateUser(UserDTO userDto) {
        User sysUser = new User();
        BeanUtils.copyProperties(userDto, sysUser);
        sysUser.setUpdateTime(LocalDateTime.now());

        if (StrUtil.isNotBlank(userDto.getPassword())) {
            sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
        }
        this.updateById(sysUser);

        userRoleService.remove(Wrappers.<UserRole>update().lambda()
                .eq(UserRole::getUserId, userDto.getUserId()));
        userDto.getRole().forEach(roleId -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(sysUser.getUserId());
            userRole.setRoleId(roleId);
            userRole.insert();
        });
        return Boolean.TRUE;
    }

    /**
     * 查询上级部门的用户信息
     *
     * @param username 用户名
     * @return R
     */
    @Override
    public List<User> listAncestorUsers(String username) {
        User sysUser = this.getOne(Wrappers.<User>query().lambda()
                .eq(User::getUsername, username));

        Dept sysDept = deptService.getById(sysUser.getDeptId());
        if (sysDept == null) {
            return null;
        }

        Integer parentId = sysDept.getParentId();
        return this.list(Wrappers.<User>query().lambda()
                .eq(User::getDeptId, parentId));
    }

    /**
     * 获取当前用户的子部门信息
     *
     * @return 子部门列表
     */
    private List<Integer> getChildDepts() {
        Integer deptId = SecurityUtils.getUser().getDeptId();
        //获取当前部门的子部门
        return deptRelationService
                .list(Wrappers.<DeptRelation>query().lambda()
                        .eq(DeptRelation::getAncestor, deptId))
                .stream()
                .map(DeptRelation::getDescendant)
                .collect(Collectors.toList());
    }

    /** 
    * @Description: 获取当前部门及其下级部门id
    * @Param: [selfDeptId] 
    * @return: java.util.List<java.lang.Integer> 
    * @Author: songwenjie 
    * @Date: 2019/4/15 
    */ 
    public List<Integer> getSelfAndChildDeptIds(Integer selfDeptId) {
        //获取当前部门的子部门
        List<Integer> childDeptIds = deptRelationService
                .list(Wrappers.<DeptRelation>query().lambda()
                        .eq(DeptRelation::getAncestor, selfDeptId))
                .stream()
                .map(DeptRelation::getDescendant)
                .collect(Collectors.toList());
        childDeptIds.add(selfDeptId);
        return childDeptIds;
    }

    /**
     * @Description: 查询部门下属的员工信息
     * @Param: [deptIds]
     * @return: java.util.List<com.elephant.framework.galaxy.aroad.module.system.vo.UserVO>
     * @Author: songwenjie
     * @Date: 2019/4/15
     */
    public List<UserVO> getSelfAndChildUsers(Integer selfDeptId){
        List<Integer> deptIds = getSelfAndChildDeptIds(selfDeptId);
        return baseMapper.getSelfAndChildUsers(deptIds);
    }

    /**
     * @Description: 查询本部门的员工信息
     * @Param: [deptId]
     * @return: java.util.List<com.elephant.framework.galaxy.aroad.module.system.vo.UserVO>
     * @Author: songwenjie
     * @Date: 2019/4/30
     */
    public List<UserVO> getSelfUsers(Integer deptId){
        return baseMapper.getSelfUsers(deptId);
    }

    /**
     * @Description: 根据用户id批量查询用户信息
     * @Param: [userIds]
     * @return: java.util.List<com.elephant.framework.galaxy.aroad.module.attendance.dto.MemberDto>
     * @Author: songwenjie
     * @Date: 2019/4/18
     */
    public List<MemberDto> getUsers(List<Integer> userIds){
        return baseMapper.getUsers(userIds);
    }

}
