package cn.com.capcloud.core.system.user;

import cn.com.capcloud.core.system.exception.CustomException;
import cn.com.capcloud.core.system.security.JwtTokenProvider;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.util.*;

@Service
public class UserService {

  @Resource
  private UserRepository userRepository;

  @Resource
  private PasswordEncoder passwordEncoder;

  @Resource
  private JwtTokenProvider jwtTokenProvider;

  @Resource
  private AuthenticationManager authenticationManager;

  @Resource
  private UserPageSortRepository userPageSortRepository;

  @Resource
  private JdbcTemplate jdbcTemplate;

  public String signing(String username, String password) {
    try {
      Authentication authentication=new UsernamePasswordAuthenticationToken(username, password);
      authenticationManager.authenticate(authentication);
      return jwtTokenProvider.createToken(username, userRepository.findByUserLoginName(username).getRoles());
    } catch (AuthenticationException e) {
      e.printStackTrace();
      throw new CustomException("10010", HttpStatus.UNPROCESSABLE_ENTITY);
    }
  }

  //生成多设备登录的用户签名
  public String signingByMultiDevice(String username, String password) {
    try {
      Authentication authentication=new UsernamePasswordAuthenticationToken(username, password);
      authenticationManager.authenticate(authentication);
      return jwtTokenProvider.createTokenByMultiDevice(username, userRepository.findByUserLoginName(username).getRoles());
    } catch (AuthenticationException e) {
      e.printStackTrace();
      throw new CustomException("10010", HttpStatus.UNPROCESSABLE_ENTITY);
    }
  }

  @Cacheable(value = "findByUserLoginName",key = "#username", unless="#result == null")
  public User findByUserLoginName(String username) throws UsernameNotFoundException {
    User user= userRepository.findByUserLoginName(username);
    //menuService.findAllByAclCachePut(user.getUserId());// 获取菜单，登录每次都走sql，其他业务调用走缓存
    return user;
  }

  @Cacheable( value= "createToken#18000",key = "#username", unless="#result == null")
  public String getCacheTokenByUsername(String username) {
    return null;
  }

  public String signup(User user) {
    if (!userRepository.existsByUserLoginName(user.getUserLoginName())) {
      user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
      userRepository.save(user);
      return jwtTokenProvider.createToken(user.getUserLoginName(), user.getRoles());
    } else {
      throw new CustomException("10010", HttpStatus.UNPROCESSABLE_ENTITY);
    }
  }
  //待测
  /*public void delete(String username) {
    userRepository.deleteByUserLoginName(username);
  }*/
  //删除token缓存
  @CacheEvict( value= "createToken#18000",key = "#username")
  public void deleteToken(String username) {
  }
  //登录（获取token）之前清空之前登录的信息，确保每次登录都是最新的登录信息
  @CacheEvict(value = "findByUserLoginName",key = "#username")
  public void deleteByUserLoginName(String username){
  }
  //重新setToken 将redis失效时间重置(#后面是设置redis过期时间 60*60*5小时=18000秒，可根据自己业务需求调整)
  @CachePut( value= "createToken#18000",key = "#username", unless="#result == null")
  public String setToken(String username,String token) {
    return token;
  }
  //重新生成token 更新缓存，使其旧的token不能继续调用资源(#后面是设置redis过期时间 60*60*5小时=18000秒，可根据自己业务需求调整)
  @CachePut( value= "createToken#18000",key = "#username", unless="#result == null")
  public String refresh(String username) {
    return jwtTokenProvider.createToken(username, userRepository.findByUserLoginName(username).getRoles());
  }
  /**
   * 保存
   */
  @Transactional
  public User save(User user){
    boolean isnew=false;
    if(user.getId()==0){
      isnew=true;

    }
    if(!isnew) {
      User oldUser=this.userRepository.findById(user.getId()).orElse(null);
      user.setCreateUserId(oldUser.getCreateUserId());
      user.setCreateUserName(oldUser.getCreateUserName());
      user.setUserCreateTime(oldUser.getUserCreateTime());
    }
    User newUser=userRepository.save(user);

    return newUser;
  }



  /**
   * 删除
   */
  public void delete(long id){
    userRepository.deleteById(id);
  }
  /**
   * 返回单个用户
   */
  public User getUser(long id){
    return userRepository.findById(id).orElse(null);
  }
  /**
   * 通过token返回用户
   */
  public User getUser(HttpServletRequest request){
    String token=getToken(request);
    if(token==null)return null;
    String username=jwtTokenProvider.getUsername(token);
    User user=findByUserLoginName(username);
    user.setRoles(null);
    return user;
  }
  /**
   * 获取token
   */
  public String getToken(HttpServletRequest request){
	Map<String, String> headerMap = new HashMap<>();
    Enumeration<String> enumeration = request.getHeaderNames();
    while (enumeration.hasMoreElements()) {
      String name	= enumeration.nextElement();
      String value = request.getHeader(name);
      headerMap.put(name, value);
    }
    String authorization=String.valueOf(headerMap.get("authorization"));
    if(authorization.equals("null")||authorization.length()==0){
      return null;
    }
    String token=authorization.substring(7);
    return token;
  }
  /**
   * 分页返回所有用户信息
   */
  public Page<User> findALL(Pageable pageable){
    return userPageSortRepository.findAll(pageable);
  }
  public List<User> findAll() {
	  return userRepository.findAll();
  }
  /**
   * 根据查询用户名分页返回所有用户信息
   */
  public Page<User> findALLByName(String userName, List<Long> userList, Pageable pageable){
    if(userName==null||userName.equals("null")){
      userName="";
    }

    return userPageSortRepository.findByConvenienceName("%"+userName+"%", userList, pageable);
  }
  public Page<User> findALLByName(String userName,List<Long> userList,long orgId,Pageable pageable){
    if(userName==null||userName.equals("null")){
      userName="";
    }

    return userPageSortRepository.findByConvenienceName("%"+userName+"%", userList, orgId,pageable);
  }
  public Page<User> findALLByName(String userName,Pageable pageable){
    if(userName==null||userName.equals("null")){
      userName="";
    }

    return userPageSortRepository.findByConvenienceName("%"+userName+"%",  pageable);
  }
  public Page<User> findALLByName(String userName,long orgId,Pageable pageable){
    if(userName==null||userName.equals("null")){
      userName="";
    }

    return userPageSortRepository.findByConvenienceName("%"+userName+"%", orgId, pageable);
  }

  public List<Long> findUserIDsByRoleId(long roleId){
    String sql="select user_id from tbl_system_roleuser where role_id="+roleId;
    List<Long> userIdList=new ArrayList<Long>();
    List<Map<String,Object>> mapList=this.jdbcTemplate.queryForList(sql);
    for(int i=0;i<mapList.size();i++) {
      long userId=Long.parseLong(String.valueOf(mapList.get(i).get("user_id")));
      userIdList.add(userId);
    }
    return userIdList;
  }

  /**
   * 根据角色名称和用户id，判断单个用户是否有该角色授权
   */
  public boolean isExistsRole(String roleId,long userId){
    boolean isExistsRole=false;
    String sql ="SELECT COUNT(1) FROM tbl_system_roleuser WHERE role_id='"+roleId+"' AND user_id="+userId;
    Integer count=this.jdbcTemplate.queryForObject(sql,Integer.class);
    if(count!=0){
      isExistsRole=true;
    }
    return isExistsRole;
  }

  public boolean isExistsRoleBySql(String roleName,long userId){
    String sql="select count(1) as count from tbl_system_role where role_id in (\n" +
            "select role_id from tbl_system_roleuser where user_id=" + userId +
            " ) and role_name='"+roleName+"'";
    List<Map<String,Object>> mapList=this.jdbcTemplate.queryForList(sql);
    if(mapList.get(0).get("count").toString().equals("0")) {
      return false;
    }else {
      return true;
    }

  }

  public Iterable<User> getAllUser(){
    return userRepository.findAll();
  }

  public List<User> getUserByRoleName(String roleName){
    String sql="select * from tbl_system_user where user_id in (select a.user_id from tbl_system_roleuser a,tbl_system_role b where a.role_id=b.role_id and b.role_name='"+roleName+"')";
    return jdbcTemplate.query(sql,new BeanPropertyRowMapper(User.class));

  }

}
