package com.zjty.tynotes.pas.service.impl;

import com.zjty.tynotes.pas.dao.*;
import com.zjty.tynotes.pas.entity.*;
import com.zjty.tynotes.pas.entity.vo.PageRequest;
import com.zjty.tynotes.pas.entity.vo.PageResponse;
import com.zjty.tynotes.pas.service.IDepartmentService;
import com.zjty.tynotes.pas.service.IUserService;
import com.zjty.tynotes.pas.task.Init;
import com.zjty.tynotes.search.subject.service.EsUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mcj
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements IUserService {
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    RedisTemplate<String,Object> defaultRedisTpl;

    @Autowired
    PasUserDao pasUserDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private RoleAuthorityDao roleAuthorityDao;
    @Autowired
    private AuthorityDao authorityDao;
    @Autowired
    private DepartmentDao departmentDao;

    @Autowired
    EsUtil esUtil;
    @Autowired
    private Init init;


    @Override
    public User updateUser(User user) {
        Optional<User> optional = pasUserDao.findById(user.getId());
        if(optional.isPresent()){
            User user1 = optional.get();
            user.setPassword(user1.getPassword());
        }
        List<UserRole> roles = new ArrayList<>();
        userRoleDao.deleteAllByUserId(user.getId());
        List<UserRole> userRoleList = new ArrayList<>();
        if(user.getRoles()!=null){
            for (Role role : user.getRoles()) {
                UserRole userRole = new UserRole();
                userRole.setUserId(user.getId());
                userRole.setRoleId(role.getId());
                userRoleList.add(userRole);
            }
            roles = userRoleDao.saveAll(userRoleList);
        }
        List<String> roleId = new ArrayList<>();
        for (UserRole userRole : roles) {
            roleId.add(userRole.getId());
        }
        List<Role> roleList = roleDao.findAllByIdIn(roleId);
        user.setRoles(roleList);
        pasUserDao.save(user);
        return user;
    }

    @Override
    public boolean deleteUserById(String id) {
        try {
            userRoleDao.deleteAllByUserId(id);
            pasUserDao.deleteById(id);
            return true;
        } catch (Exception e) {
            logger.error("mongodb删除用户失败");
        }
        return false;
    }

    @Override
    public User registerUser(User user) {
       if(findUserByUsername(user.getUsername())!=null){
          return user;
       }
        User save = pasUserDao.save(user);
        esUtil.createIndex(save.getId());
        return save;
    }

    @Override
    public User findUserByUsername(String username) {
        return pasUserDao.findByUsername(username);
    }

    @Override
    public List<User> findUserByName(String name) {
        List<User> users = pasUserDao.findAllByUsername(name);
        for (User user : users) {
            List<String> roleIds = new ArrayList<>();
            List<UserRole> userRoles = userRoleDao.findAllByUserId(user.getId());
            if(userRoles!=null){
                for (UserRole userRole : userRoles) {
                    String roleId = userRole.getRoleId();
                    roleIds.add(roleId);
                }
            }
            List<Role> roles = roleDao.findAllByIdIn(roleIds);
            user.setRoles(roles);
        }
        return users;
    }

    @Override
    public User findUserById(String id) {
        Optional<User> byId = pasUserDao.findById(id);
        List<String> roleIds = new ArrayList<>();
        User user = null;
        if(byId.isPresent()){
            user = byId.get();
            List<UserRole> userRoles = userRoleDao.findAllByUserId(user.getId());
            if(userRoles!=null){
                for (UserRole userRole : userRoles) {
                    roleIds.add(userRole.getRoleId());
                }
            }

            List<Role> roles = roleDao.findAllByIdIn(roleIds);
            if(roles!=null){
                for (Role role : roles) {
                    List<RoleAuthority> roleAuthorities = roleAuthorityDao.findAllByRoleId(role.getId());
                    List<String> authorityIds = new ArrayList<>();
                    if(roleAuthorities!=null){
                        for (RoleAuthority roleAuthority : roleAuthorities) {
                            authorityIds.add(roleAuthority.getAuthorityId());
                        }
                    }
                    List<Authority> authorities = authorityDao.findAllByIdIn(authorityIds);
                    role.setAuthorities(authorities);
                }
            }
            user.setRoles(roles);
        }
        return user;
    }

    @Override
    public List<User> findUserByIds(List<String> ids) {
        return pasUserDao.findAllByIdIn(ids);
    }

    @Override
    public List<User> findAll() {
        List<User> userList = new ArrayList<>();
        List<User> users = pasUserDao.findAll();
        for (User user : users) {
            if(!user.getUsername().equals("root")){
                List<UserRole> userRoles = userRoleDao.findAllByUserId(user.getId());
                List<String> roleIds = new ArrayList<>();
                for (UserRole userRole : userRoles) {
                    roleIds.add(userRole.getRoleId());
                }
                List<Role> roles = roleDao.findAllByIdIn(roleIds);
                user.setRoles(roles);
                userList.add(user);
            }
        }
        return userList;
    }

    @Override
    public String addUserCount(String username) {
        Object integer1 = defaultRedisTpl.opsForValue().get(username);

        Integer value = (Integer)integer1;
        String sysManagerName = "root";
        Integer count = 4;
        if(sysManagerName.equals(username)){
            return "";
        }
        if(integer1!=null){
           if(value>=count) {
               Query query = new Query(Criteria.where("username").is(username));
               Update update = new Update();
               update.set("clock", 1);
               mongoTemplate.updateFirst(query, update, User.class);
               return "账户已锁定";
           }else {
               Integer integer = value+1;
               defaultRedisTpl.opsForValue().set(username,integer,1,TimeUnit.DAYS);
               int i1 = 5 - integer;
               return "还有"+i1+"次机会";
           }
        }else {
            defaultRedisTpl.opsForValue().set(username,1);
            return "还有4次机会";
        }
    }

    @Override
    public User addUser(User user) {
        String encode = bCryptPasswordEncoder.encode("qwer1234");
        user.setPassword(encode);
//        user.setPassword("qwer1234");
        List<Role> roles = user.getRoles();
        List<UserRole> userRoles = new ArrayList<>();
        List<User> users = pasUserDao.findAll();
        for (User user1 : users) {
            if(user1.getUsername().equals(user.getUsername())){
                return null;
            }
        }
        User save = pasUserDao.save(user);
        List<String> ids = new ArrayList<>();
        if(roles!=null){
            for (Role role : roles) {
                String id = role.getId();
                UserRole userRole = new UserRole();
                userRole.setUserId(user.getId());
                userRole.setRoleId(id);
                userRoles.add(userRole);
                ids.add(role.getId());
            }
            userRoleDao.saveAll(userRoles);
        }
        List<Role> roleList = roleDao.findAllByIdIn(ids);
        save.setRoles(roleList);
        save.setDepartmentIds(user.getDepartmentIds());
        return save;
    }

    @Override
    public boolean isHaveAuthority(String userId, String authorityName) {
        List<UserRole> userRoles = userRoleDao.findAllByUserId(userId);
        List<String> roleIds = new ArrayList<>();
        for (UserRole userRole : userRoles) {
            roleIds.add(userRole.getRoleId());
        }
        List<RoleAuthority> roleAuthorities = roleAuthorityDao.findAllByRoleIdIn(roleIds);
        List<String> authorityIds = new ArrayList<>();
        for (RoleAuthority roleAuthority : roleAuthorities) {
            authorityIds.add(roleAuthority.getAuthorityId());
        }
        List<Authority> authorities = authorityDao.findAllByIdIn(authorityIds);
        for (Authority authority : authorities) {
            if(authorityName.equals(authority.getName())){
                return true;
            }
        }
        return false;
    }

    @Override
    public List<User> findParentManager(String userId) {
        List<User> users = new ArrayList<>();
        List<UserRole> userRoles = userRoleDao.findAllByUserId(userId);
        List<String> roleIds = new ArrayList<>();
        for (UserRole userRole : userRoles) {
            String roleId = userRole.getRoleId();
            roleIds.add(roleId);
        }
        List<Role> roles = roleDao.findAllByIdIn(roleIds);
        for (Role role : roles) {
            List<String> roleIds2 = new ArrayList<>();
            List<String> userIds = new ArrayList<>();
            if(("1").equals(role.getIsLeader())){
                List<Role> roles1 = roleDao.findAllByDepartmentIdAndIsLeader(
                        role.getDepartmentId(), "0");
                for (Role role1 : roles1) {
                    roleIds2.add(role1.getId());
                }
                List<UserRole> userRoleList = userRoleDao.findAllByRoleIdIn(roleIds2);
                for (UserRole userRole : userRoleList) {
                    userIds.add(userRole.getUserId());
                }
                List<User> userList = pasUserDao.findAllByIdIn(userIds);
                users.addAll(userList);
            }else{
                Optional<Department> op = departmentDao.findById(role.getDepartmentId());
                if(op.isPresent()){
                    Department department = op.get();
                    String parentId = department.getParentId();
                    List<Role> roles1 = roleDao.findAllByDepartmentIdAndIsLeader(
                            role.getDepartmentId(), "0");
                    for (Role role1 : roles1) {
                        roleIds2.add(role1.getId());
                    }
                    List<UserRole> userRoleList = userRoleDao.findAllByRoleIdIn(roleIds2);
                    for (UserRole userRole : userRoleList) {
                        userIds.add(userRole.getUserId());
                    }
                    List<User> userList = pasUserDao.findAllByIdIn(userIds);
                    users.addAll(userList);
                }
            }
        }
        return null;
    }

    @Override
    public List<User> findUserList(String userId,String authoryName){
        List<String> departmentList = findDepartmentList(userId,authoryName);
        List<User> all = pasUserDao.findAll();
        List<User> users = new ArrayList<>();
        if(all!=null){
            for (User user : all) {
                List<String> departmentIds = user.getDepartmentIds();

                if(departmentIds!=null){
                    for (String departId : departmentIds) {
                        if(departmentList.contains(departId)){
                            users.add(user);
                            break;
                        }
                    }
                }

            }
        }
        for (User user : users) {
            List<UserRole> userRoles = userRoleDao.findAllByUserId(user.getId());
            List<String> roleIds = new ArrayList<>();
            if(userRoles!=null){
                for (UserRole userRole : userRoles) {
                    roleIds.add(userRole.getRoleId());
                }
            }
            List<Role> roles = roleDao.findAllByIdIn(roleIds);
            if(roles!=null){
                for (Role role : roles) {
                    List<RoleAuthority> roleAuthorities = roleAuthorityDao.findAllByRoleId(role.getId());
                    List<String> authorityIds = new ArrayList<>();
                    for (RoleAuthority roleAuthority : roleAuthorities) {
                        authorityIds.add(roleAuthority.getAuthorityId());
                    }
                    List<Authority> authorities = authorityDao.findAllByIdIn(authorityIds);
                    role.setAuthorities(authorities);
                }
            }
            user.setRoles(roles);
        }

        return users;

    }

    /**
     * 根据人员id查询可查看的所有人员
     * @param userId
     * @return
     */
    @Override
    public List<String> findUsers(String userId){
        String authorityName = "查看任务";
        List<User> userList = findUserList(userId, authorityName);
        List<String> userIds = new ArrayList<>();
        for (User user : userList) {
            userIds.add(user.getId());
        }
        return userIds;
    }

    @Override
    public Object encryPas() {
        List<User> users = pasUserDao.findAll();
        if(users!=null){
            for (User user : users) {
                String encode = bCryptPasswordEncoder.encode(user.getPassword());
                user.setPassword(encode);
            }
        }
        return pasUserDao.saveAll(users);
    }

    @Override
    public Object deleteRoot() {
        User root = pasUserDao.findByUsername("root");
        List<UserRole> userRoles = userRoleDao.findAllByUserId(root.getId());
        Role role = roleDao.findAllByName("管理员");
        userRoleDao.deleteAllByUserId(root.getId());
        UserRole userRole = new UserRole(null,root.getId(),role.getId());
        userRoleDao.save(userRole);

        List<String> auname = new ArrayList<>();
        auname.add("用户管理");
        auname.add("权限管理");
        auname.add("角色管理");
        auname.add("考勤管理");
        auname.add("部门管理");
        List<RoleAuthority> roleAuthoritieList = new ArrayList<>();
        List<Authority> authorities = authorityDao.findAllByNameIn(auname);
        if(authorities==null||authorities.size()==0){
            List<Authority> authorityList = new ArrayList<>();
            authorityList.add(new Authority(null,"用户管理","用户管理"));
            authorityList.add(new Authority(null,"权限管理","权限管理"));
            authorityList.add(new Authority(null,"角色管理","角色管理"));
            authorityList.add(new Authority(null,"考勤管理","考勤管理"));
            authorityList.add(new Authority(null,"部门管理","部门管理"));
            authorities = authorityDao.saveAll(authorityList);
        }
        List<RoleAuthority> roleAuthorities = roleAuthorityDao.findAllByRoleId(role.getId());
        if(roleAuthorities==null||roleAuthorities.size()==0){
            for (Authority authority : authorities) {
                roleAuthoritieList.add(new RoleAuthority(null,role.getId(),authority.getId()));
            }
            roleAuthorityDao.saveAll(roleAuthoritieList);
        }
        return authorities;
    }

    /**
     * 查询可查看的部门id集合
     * @param id
     * @return
     */
    private List<String> findDepartmentList(String id,String authoryName) {
        List<UserRole> userRoles = userRoleDao.findAllByUserId(id);
        List<String> roleIds = new ArrayList<>();
        List<String> departmentIds = new ArrayList<>();
        for (UserRole userRole : userRoles) {
            roleIds.add(userRole.getRoleId());
        }
        List<Role> roles = roleDao.findAllByIdIn(roleIds);
        for (Role role : roles) {
            List<RoleAuthority> roleAuthorities = roleAuthorityDao.findAllByRoleId(role.getId());
            List<String> authorityIds = new ArrayList<>();
            for (RoleAuthority roleAuthority : roleAuthorities) {
                authorityIds.add(roleAuthority.getAuthorityId());
            }
            Authority authority = authorityDao.findByIdInAndName(authorityIds, authoryName);
            if(authority!=null){
                String departmentId = role.getDepartmentId();
                departmentIds.add(departmentId);
            }
        }
        List<String> departmentIdList = new ArrayList<>();

        getDepartments(departmentIdList,departmentIds);

        return departmentIdList;
    }

    /**
     * 递归获取所有的部门列表
     * @param departmentIdList
     * @param departmentIds
     */
    public void getDepartments(List<String> departmentIdList,List<String> departmentIds) {
        for (String string : departmentIds) {
            if(departmentIdList.contains(string)){
                continue;
            }

            List<Department> departmentList = departmentDao.findAllByParentId(string);
            List<String> departments = new ArrayList<>();
            for (Department department : departmentList) {
                departments.add(department.getId());
            }
            departmentIdList.add(string);
            getDepartments(departmentIdList,departments);
        }
    }

    /**
     * 供考勤模块的审批流程使用的接口
      * @param departmentId
     * @return  返回部门等级
     */
   @Override
   public String getDepartmentLevel(String departmentId){
       Optional<Department> optional = departmentDao.findById(departmentId);
       Department department = null;
       if(optional.isPresent()){
           department = optional.get();
           String level = department.getLevel();
           return level;
       }
       return null;
   }

    @Override
    public String getParentDepartmentLevel(String departmentId) {
        Optional<Department> optional = departmentDao.findById(departmentId);
        Department department = null;
        if(optional.isPresent()){
            department = optional.get();
            String parentId = department.getParentId();
            Optional<Department> byId = departmentDao.findById(parentId);
            if(byId.isPresent()){
                Department department1 = byId.get();
                String level = department1.getLevel();
                return level;
            }
        }
        return null;
    }

    /**
     * 根据用户id判断某个用户是否有该部门的审批权限
     * @param userId
     * @param departmentId
     * @return
     */
    @Override
    public boolean findUsersByDepartmentAndAuthority(String userId, String departmentId) {
        List<UserRole> userRoles = userRoleDao.findAllByUserId(userId);
        List<String> roleIds = new ArrayList<>();
        if(userRoles!=null){
            userRoles.forEach(userRole -> roleIds.add(userRole.getRoleId()));
        }
        List<Role> roles = roleDao.findAllByIdIn(roleIds);
        if(roles!=null){
            for (Role role : roles) {
                List<RoleAuthority> roleAuthorities = roleAuthorityDao.findAllByRoleId(role.getId());
                List<String> authorityIds = new ArrayList<>();
                List<String> authNames = new ArrayList<>();
                if(roleAuthorities!=null){
                    roleAuthorities.forEach(roleAuthority -> authorityIds.add(roleAuthority.getAuthorityId()));
                }
                List<Authority> authorities = authorityDao.findAllByIdIn(authorityIds);
                if(authorities!=null){
                    authorities.forEach(authority -> authNames.add(authority.getName()));
                }
                if(authNames.contains("审批权限")&&role.getDepartmentId().equals(departmentId)){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 重置密码
     * @param id
     * @return
     */
    @Override
    @Transactional
    public boolean replacePass(String id) {
        Optional<User> optional = pasUserDao.findById(id);
        if(optional.isPresent()){
            User user = optional.get();
            user.setPassword(bCryptPasswordEncoder.encode("qwer1234"));
            pasUserDao.save(user);
            return true;
        }
        return false;
    }

    /**
     * 是否为上级，并且拥有修改任务权限
     * @param id
     * @param userId
     * @return
     */
    @Override
    public boolean judgeParent(String id, String userId) {
        Optional<User> optional = pasUserDao.findById(userId);
        boolean flag = false;
        if(optional.isPresent()){
            User user = optional.get();
            List<String> departmentIdList = user.getDepartmentIds();
            List<UserRole> userRoles2 = userRoleDao.findAllByUserId(id);
            List<String> roleIds = new ArrayList<>();
            List<String> roleIds2 = new ArrayList<>();

            if(userRoles2!=null){
                userRoles2.forEach(userRole -> roleIds.add(userRole.getRoleId()));
                List<Role> roles = roleDao.findAllByIdIn(roleIds);
                List<String> departIds = new ArrayList<>();
                if(roles!=null){
                    roles.forEach(role -> {
                        List<String> authorityIds = new ArrayList<>();
                        List<RoleAuthority> roleAuthorities = roleAuthorityDao.findAllByRoleId(role.getId());
                        if(roleAuthorities!=null){
                            roleAuthorities.forEach(roleAuthority -> {
                                authorityIds.add(roleAuthority.getAuthorityId());
                            });
                            List<Authority> authorities = authorityDao.findAllByIdIn(authorityIds);
                            if(authorities!=null){
                                authorities.forEach(authority -> {
                                    if(authority.getName().equals("修改任务")){
                                        departIds.add(role.getDepartmentId());
                                    }
                                });
                            }
                        }
                    });
                }


                List<String> departmentIds = new ArrayList<>();//自身或者上级部门
                departmentIdList.forEach(deId -> {
                    List<String> parentDepartIds = findParentDepartIds(deId, new ArrayList<String>());
                    if(parentDepartIds!=null){
                        parentDepartIds.forEach(str->{
                            if(!departmentIds.contains(str)){
                                departmentIds.add(str);
                            }
                        });
                    }
                });

                for (String str : departmentIds) {
                    if(departIds.contains(str)){
                        flag = true;
                    }
                }

            }
        }

        return flag;
    }

    public List<String> findParentDepartIds(String departmentId,List<String> departmentIds){
        departmentIds.add(departmentId);
        Optional<Department> optional = departmentDao.findById(departmentId);
        Department department = null;
        if(optional.isPresent()){
            department = optional.get();
            String parentId = department.getParentId();
            if(StringUtils.isNotBlank(parentId)){
                findParentDepartIds(parentId,departmentIds);
            }else{
                if(!departmentIds.contains(parentId)){
                    departmentIds.add(parentId);
                }
            }

        }
        return departmentIds;
    }


    /**
     * 查询所有上级部门
     * @param departIds 需要传入的用户部门集合
     * @param departmentIds 用来存所有上级部门id集合
     * @return
     */
   public List<String> findParentDepartIds(List<String> departIds,List<String> departmentIds){
       List<String> ids = new ArrayList<>();
       departIds.forEach(str->{
           Department department = null;
           Optional<Department> optional = departmentDao.findById(str);
           if(optional.isPresent()){
               department = optional.get();
               if((!department.getLevel().equals("1"))&&(!department.getLevel().equals("2"))){
                   if(!departmentIds.contains(str)){
                       if(optional.isPresent()){
                           String parentId = department.getParentId();
                           ids.add(parentId);
                       }
                   }
               }
           }
           departmentIds.add(str);
       });
       findParentDepartIds(ids,departmentIds);
       return departmentIds;
   }


}

