package com.jeeww.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.jeeww.core.dao.QueryDAO;
import com.jeeww.core.syspojo.AgtbRoleInfo;
import com.jeeww.core.syspojo.AgtbRoleResourceRel;
import com.jeeww.core.syspojo.AgtbUserInfo;
import com.jeeww.core.syspojo.AgtbUserRoleRel;
import com.jeeww.dto.MenuInfoDTO;
import com.jeeww.dto.ResourceInfoDTO;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    protected QueryDAO queryDAO;
    static Logger logger = Logger.getLogger(UserDetailsServiceImpl.class);
    protected static Map<String, JSONArray> normalRequestUrls = new HashMap<String, JSONArray>();
    boolean isEnabled = true;
    boolean isAccountNonExpired = true;
    boolean isCredentialsNonExpired = true;
    boolean isAccountNonLocked = true;

    /**
     * 功能描述：根据当前登录人获得相关信息.
     * @param username 登录账号名称.
     * @return UserDetails 当前登录人相关信息对象.
     */
    public UserDetails loadUserByUsername(final String username) {
        AgtbUserInfo user = new AgtbUserInfo();
        String hql = "FROM AgtbUserInfo u where u.loginName=:loginName";
        user.setLoginName(username);
        // 通过数据库取得 当前用户的 资源权限信息
        List<AgtbUserInfo> list = null;
        try {
            list = queryDAO.queryByHQL(hql, user);
            if (list != null && !list.isEmpty() && list.size() == 1) {
                AgtbUserInfo agtbUserInfo = list.get(0);
                CustomerUserDetails userDetail = initUserDetail(agtbUserInfo);
                // AgtbUserConfigrationInfo agtbUserConfigrationInfo = agtbUserInfo.getAgtbUserConfigrationInfo();
                AgtbRoleInfo role = new AgtbRoleInfo(); // 查询角色信息.
                role.setRoleName("ROLE_USER");
                role.setRoleId("1");
                Collection<GrantedAuthority> authorities = obtionGrantedAuthorities(agtbUserInfo);
                userDetail.setAuthorities(authorities);
                Set<AgtbRoleInfo> roles = getUserRoles(agtbUserInfo);
                userDetail.setRoles(roles);
                List<MenuInfoDTO> menuList = getLoginUserMenu(agtbUserInfo);
                userDetail.setMenuList(menuList);
                return userDetail;
            } else {
                throw new UsernameNotFoundException(username);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 方法描述：获得当前登录人菜单信息.
     * @param agtbUserInfo 用户对象.
     * @return Set<AgtbRoleInfo> 当前登录人角色集合.
     */
    private List<MenuInfoDTO> getLoginUserMenu(AgtbUserInfo agtbUserInfo) throws Exception {
        List<MenuInfoDTO> rootMenuList = queryDAO.queryBySQLNamedQuery("queryLoginUserRootMenu", agtbUserInfo,
                MenuInfoDTO.class); // 查询当前登录人拥有的导航菜单
        List<MenuInfoDTO> newMenuList = getSubMenu(rootMenuList, agtbUserInfo);
        return newMenuList;
    }

    private List<MenuInfoDTO> getSubMenu(List<MenuInfoDTO> menuList, AgtbUserInfo agtbUserInfo) throws Exception {
        List<MenuInfoDTO> newMenuList = new ArrayList<MenuInfoDTO>();
        for (int i = 0; i < menuList.size(); i++) {
            MenuInfoDTO menuInfoDTO = menuList.get(i);
            JSONArray accordingTreeNodes = getTreeNodesAsMenu(menuInfoDTO, agtbUserInfo);
            menuInfoDTO.setAccordingTreeNodes(accordingTreeNodes);
            newMenuList.add(menuInfoDTO);
        }
        return newMenuList;
    }

    private JSONArray getMenuResource(final MenuInfoDTO menuInfoDTO, final AgtbUserInfo agtbUserInfo) throws Exception {
        JSONArray treeNodes = new JSONArray(); // 菜单下面的资源信息
        SecuritySearchModel securitySearchModel = new SecuritySearchModel();
        securitySearchModel.setMenuId(menuInfoDTO.getMenuId());
        securitySearchModel.setUserId(agtbUserInfo.getUserId());
        List<ResourceInfoDTO> resources = queryDAO.queryBySQLNamedQuery("queryLoginUserMenuResources",
                securitySearchModel, ResourceInfoDTO.class); // 查询菜单下面的资源信息
        for (ResourceInfoDTO resourceInfoDTO : resources) {
            JSONObject node = new JSONObject(); // 单个子节点
            node.put("id", resourceInfoDTO.getResourceId());
            // node.put("id", Integer.parseInt(resourceInfoDTO.getResourceId()));
            node.put("text", resourceInfoDTO.getResourceName());
            JSONObject attributes = new JSONObject();
            attributes.put("url", resourceInfoDTO.getResourceUrl());
            node.put("attributes", attributes);
            treeNodes.add(node);
        }
        return treeNodes;
    }

    private JSONArray getTreeNodesAsMenu(final MenuInfoDTO menuInfoDTO, final AgtbUserInfo agtbUserInfo)
            throws Exception {
        JSONArray treeNodes = new JSONArray(); // 导航条下面的树节点
        SecuritySearchModel securitySearchModel = new SecuritySearchModel();
        securitySearchModel.setMenuId(menuInfoDTO.getMenuId());
        securitySearchModel.setUserId(agtbUserInfo.getUserId());
        List<MenuInfoDTO> subMenuList = queryDAO.queryBySQLNamedQuery("queryLoginUserSubMenu", securitySearchModel,
                MenuInfoDTO.class); // 查询子菜单
        for (MenuInfoDTO subMenuInfoDTO : subMenuList) {
            JSONObject node = new JSONObject(); // 单个子节点
            node.put("id", Integer.parseInt(subMenuInfoDTO.getMenuId()));
            node.put("text", subMenuInfoDTO.getMenuName());
            // 获得菜单的资源信息
            JSONArray childrenTreeNodesResources = getMenuResource(subMenuInfoDTO, agtbUserInfo);
            JSONArray childrenMenu = new JSONArray(); // 菜单子节点
            if (!childrenTreeNodesResources.isEmpty()) {
                childrenMenu.addAll(childrenTreeNodesResources); // 往子菜单中增加资源信息
            }

            if (isHaveChildren(subMenuInfoDTO, agtbUserInfo)) {
                childrenMenu.addAll(getTreeNodesAsMenu(subMenuInfoDTO, agtbUserInfo));
            }
            if (!childrenMenu.isEmpty()) {
                node.put("children", childrenMenu);
            }
            treeNodes.add(node);
        }
        JSONArray treeNodesResources = getMenuResource(menuInfoDTO, agtbUserInfo);
        treeNodes.addAll(treeNodesResources);
        return treeNodes;
    }

    private boolean isHaveChildren(MenuInfoDTO menuInfoDTO, AgtbUserInfo agtbUserInfo) throws Exception {
        SecuritySearchModel securitySearchModel = new SecuritySearchModel();
        securitySearchModel.setMenuId(menuInfoDTO.getMenuId());
        securitySearchModel.setUserId(agtbUserInfo.getUserId());
        int count = queryDAO.getCountBySQLNamedQuery("checkIsHaveSubNodes", securitySearchModel); // 查询子菜单
        if (count > 0) {
            return true;
        }
        return false;
    }

    /**
     * 方法描述：获得当前登录人角色集合.
     * @param agtbUserInfo 用户对象.
     * @return Set<AgtbRoleInfo> 当前登录人角色集合.
     */
    private Set<AgtbRoleInfo> getUserRoles(final AgtbUserInfo agtbUserInfo) {
        Set<AgtbRoleInfo> roles = new HashSet<AgtbRoleInfo>();
        Set<AgtbUserRoleRel> agtbUserRoleRelsSet = agtbUserInfo.getAgtbUserRoleRels(); // 获得当前登录人拥有的角色集合
        for (AgtbUserRoleRel agtbUserRoleRel : agtbUserRoleRelsSet) {
            AgtbRoleInfo agtbRoleInfo = agtbUserRoleRel.getAgtbRoleInfo();
            roles.add(agtbRoleInfo);
        }
        return roles;
    }

    /**
     * 方法描述：初始化userDetail.
     * @param agtbUserInfo agtbUserInfo
     * @return CustomerUserDetails 初始化对象.
     */
    private CustomerUserDetails initUserDetail(final AgtbUserInfo agtbUserInfo) {
        CustomerUserDetails userDetail = new CustomerUserDetails();
        userDetail.setEnabled(isEnabled);
        userDetail.setAccountNonExpired(isAccountNonExpired);
        userDetail.setCredentialsNonExpired(isCredentialsNonExpired);
        userDetail.setAccountNonLocked(isAccountNonLocked);
        userDetail.setNormalRequestUrls(normalRequestUrls);
        userDetail.setUserInfo(agtbUserInfo);
        userDetail.setUserName(agtbUserInfo.getLoginName());
        userDetail.setPassword(agtbUserInfo.getLoginPassword());
        return userDetail;
    }

    /**
     * 方法描述：取得用户的权限
     * @param AgtbUserInfo user
     * @return obtionGrantedAuthorities 初始化对象.
     */
    private Set<GrantedAuthority> obtionGrantedAuthorities(final AgtbUserInfo user) {
        Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
        Set<AgtbUserRoleRel> userRoleRels = user.getAgtbUserRoleRels();
        for (AgtbUserRoleRel userRoleRel : userRoleRels) {
            AgtbRoleInfo agtbRoleInfo = userRoleRel.getAgtbRoleInfo();
            Set<AgtbRoleResourceRel> agtbRoleResourceRels = agtbRoleInfo.getAgtbRoleResourceRels();
            for (AgtbRoleResourceRel agtbRoleResourceRel : agtbRoleResourceRels) {
                authSet.add(new SimpleGrantedAuthority(agtbRoleResourceRel.getAgtbResourceInfo().getResourceId()));
            }
        }
        return authSet;
    }
}
