package com.cm.common.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cm.common.config.properties.AccessControl;
import com.cm.common.pojo.bos.RoleBO;
import com.cm.common.pojo.bos.RoleGrantedAuthority;
import com.cm.common.pojo.bos.RoleMenuBO;
import com.cm.common.service.IRbacService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;

/**
 * @ClassName: RbacServiceImpl
 * @Description: 权限校验
 * @Author: WangGeng
 * @Date: 2019-05-30 15:16
 * @Version: 1.0
 **/
@Component("rbacService")
public class RbacServiceImpl implements IRbacService {

    private static final Logger LOG = LoggerFactory.getLogger(RbacServiceImpl.class);
    /**
     * 根路径
     */
    private static final String ANT_PATH_BASE = "/";
    @Autowired
    private AccessControl accessControl;

    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        boolean hasPermission = false;
        Object object = authentication.getPrincipal();
        if (object == null || "anonymousUser".equals(object.toString())) {
            return hasPermission;
        }
        String requestURI = request.getRequestURI();
        Collection<? extends GrantedAuthority> grantedAuthorities = authentication.getAuthorities();
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        String contextPath = request.getContextPath();

        for (GrantedAuthority grantedAuthority : grantedAuthorities) {
            RoleGrantedAuthority roleGrantedAuthority;
            if (grantedAuthority instanceof RoleGrantedAuthority) {
                LOG.debug("统一用户登录");
                roleGrantedAuthority = (RoleGrantedAuthority) grantedAuthority;
            } else {
                LOG.debug("客户端登录");
                JSONObject authorityObject = JSONObject.parseObject(grantedAuthority.toString().replace("_wg_", ","));
                if (StringUtils.contains(authorityObject.getString("authority"), "_ALL")) {
                    LOG.debug("管理员登录客户端");
                    roleGrantedAuthority = new RoleGrantedAuthority(authorityObject.getString("authority"));
                } else {
                    LOG.debug("普通用户登录客户端");
                    RoleBO roleBO = new RoleBO();
                    roleBO.setRoleId(authorityObject.getString("roleId"));
                    roleBO.setRoleName(authorityObject.getString("roleName"));
                    roleBO.setApiSaveMenu(JSON.parseArray(authorityObject.getString("apiSaveMenu"), RoleMenuBO.class));
                    roleBO.setApiDeleteMenu(JSON.parseArray(authorityObject.getString("apiDeleteMenu"), RoleMenuBO.class));
                    roleBO.setApiUpdateMenu(JSON.parseArray(authorityObject.getString("apiSaveMenu"), RoleMenuBO.class));
                    roleBO.setApiQueryMenu(JSON.parseArray(authorityObject.getString("apiQueryMenu"), RoleMenuBO.class));
                    roleBO.setResourceSaveMenu(JSON.parseArray(authorityObject.getString("resourceSaveMenu"), RoleMenuBO.class));
                    roleBO.setResourceDeleteMenu(JSON.parseArray(authorityObject.getString("resourceDeleteMenu"), RoleMenuBO.class));
                    roleBO.setResourceUpdateMenu(JSON.parseArray(authorityObject.getString("resourceUpdateMenu"), RoleMenuBO.class));
                    roleBO.setResourceQueryMenu(JSON.parseArray(authorityObject.getString("resourceQueryMenu"), RoleMenuBO.class));
                    roleBO.setRouteSaveMenu(JSON.parseArray(authorityObject.getString("routeSaveMenu"), RoleMenuBO.class));
                    roleBO.setRouteUpdateMenu(JSON.parseArray(authorityObject.getString("routeUpdateMenu"), RoleMenuBO.class));
                    roleBO.setRouteQueryMenu(JSON.parseArray(authorityObject.getString("routeQueryMenu"), RoleMenuBO.class));
                    roleGrantedAuthority = new RoleGrantedAuthority(authorityObject.getString("authority"), roleBO);
                }
            }
            if (StringUtils.contains(roleGrantedAuthority.getAuthority(), "_ALL")) {
                LOG.debug("权限校验URI：{}，当前用户为最高管理员，有所有权限", requestURI);
                hasPermission = true;
                break;
            }
            // 放行权限
            if (hasPassPermission(contextPath, requestURI, roleGrantedAuthority, antPathMatcher)) {
                LOG.debug("权限校验URI：{}，有新增权限", requestURI);
                hasPermission = true;
                break;
            }
            // 新增权限
            if (hasSavePermission(contextPath, requestURI, roleGrantedAuthority, antPathMatcher)) {
                LOG.debug("权限校验URI：{}，有新增权限", requestURI);
                hasPermission = true;
                break;
            }
            // 删除权限
            if (hasDeletePermission(contextPath, requestURI, roleGrantedAuthority, antPathMatcher)) {
                LOG.debug("权限校验URI：{}，有删除权限", requestURI);
                hasPermission = true;
                break;
            }
            // 修改权限
            if (hasUpdatePermission(contextPath, requestURI, roleGrantedAuthority, antPathMatcher)) {
                LOG.debug("权限校验URI：{}，有修改权限", requestURI);
                hasPermission = true;
                break;
            }
            // 查询权限
            if (hasQueryPermission(contextPath, requestURI, roleGrantedAuthority, antPathMatcher)) {
                LOG.debug("权限校验URI：{}，有查询权限", requestURI);
                hasPermission = true;
                break;
            }
        }
        return hasPermission;
    }

    /**
     * 放行权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasPassPermission(String contextPath, String uri, RoleGrantedAuthority roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        if ((contextPath + ANT_PATH_BASE).equals(uri)) {
            return true;
        }
        List<String> passPaths = accessControl.getPassPaths();
        for (String passPath : passPaths) {
            if (antPathMatcher.match(contextPath + passPath, uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 接口的新增权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasSavePermission(String contextPath, String uri, RoleGrantedAuthority roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> savePaths = accessControl.getSavePaths();
        // 匹配接口
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getApiSaveMenu()) {
            for (String savePath : savePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getApiPrefix() + savePath, uri)) {
                    return true;
                }
            }
        }
        // 匹配资源
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getResourceSaveMenu()) {
            for (String savePath : savePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getResourcePrefix() + savePath, uri)) {
                    return true;
                }
            }
        }
        // 匹配路由
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getRouteSaveMenu()) {
            for (String savePath : savePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getRoutePrefix() + savePath, uri)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 接口的删除权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasDeletePermission(String contextPath, String uri, RoleGrantedAuthority roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> deletePaths = accessControl.getDeletePaths();
        // 匹配接口
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getApiDeleteMenu()) {
            for (String deletePath : deletePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getApiPrefix() + deletePath, uri)) {
                    return true;
                }
            }
        }
        // 匹配资源
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getResourceDeleteMenu()) {
            for (String deletePath : deletePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getResourcePrefix() + deletePath, uri)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 接口的修改权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasUpdatePermission(String contextPath, String uri, RoleGrantedAuthority roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> updatePaths = accessControl.getUpdatePaths();
        // 匹配接口
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getApiUpdateMenu()) {
            for (String updatePath : updatePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getApiPrefix() + updatePath, uri)) {
                    return true;
                }
            }
        }
        // 匹配资源
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getResourceUpdateMenu()) {
            for (String updatePath : updatePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getResourcePrefix() + updatePath, uri)) {
                    return true;
                }
            }
        }
        // 匹配路由
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getRouteUpdateMenu()) {
            for (String updatePath : updatePaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getRoutePrefix() + updatePath, uri)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 接口的查询权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasQueryPermission(String contextPath, String uri, RoleGrantedAuthority roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> queryPaths = accessControl.getQueryPaths();
        // 匹配接口
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getApiQueryMenu()) {
            for (String queryPath : queryPaths) {
                String queryAntPath = contextPath + roleMenuBO.getApiPrefix() + queryPath;
                if (antPathMatcher.match(queryAntPath, uri)) {
                    return true;
                }
            }
        }
        // 匹配资源
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getResourceQueryMenu()) {
            for (String queryPath : queryPaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getResourcePrefix() + queryPath, uri)) {
                    return true;
                }
            }
        }
        // 匹配路由
        for (RoleMenuBO roleMenuBO : roleGrantedAuthority.getRouteQueryMenu()) {
            for (String queryPath : queryPaths) {
                if (antPathMatcher.match(contextPath + roleMenuBO.getRoutePrefix() + queryPath, uri)) {
                    return true;
                }
            }
        }
        return false;
    }

}
