package ink.wgink.common.service.rbac.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import ink.wgink.common.service.rbac.IRbacService;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.pojo.bos.RoleGrantedAuthorityBO;
import ink.wgink.properties.AccessControlProperties;
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);
    @Autowired
    private AccessControlProperties accessControlProperties;

    /**
     * 根路径
     */
    private static final String ANT_PATH_BASE = "/";

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

        // 校验权限
        for (GrantedAuthority grantedAuthority : grantedAuthorities) {
            RoleGrantedAuthorityBO roleGrantedAuthority;
            if (grantedAuthority instanceof RoleGrantedAuthorityBO) {
                LOG.debug("统一用户登录");
                roleGrantedAuthority = (RoleGrantedAuthorityBO) grantedAuthority;
            } else {
                LOG.debug("客户端登录");
                JSONObject authorityObject = JSONObject.parseObject(grantedAuthority.toString().replace("_wg_", ","));
                if (StringUtils.contains(authorityObject.getString("authority"), ISystemConstant.ADMIN)) {
                    LOG.debug("管理员登录客户端");
                    roleGrantedAuthority = new RoleGrantedAuthorityBO(authorityObject.getString("authority"));
                } else {
                    LOG.debug("普通用户登录客户端");
                    String roleId = authorityObject.getString("roleId");
                    String roleName = authorityObject.getString("roleName");
                    List<String> menus = JSON.parseArray(authorityObject.getString("menus"), String.class);
                    List<String> inserts = JSON.parseArray(authorityObject.getString("inserts"), String.class);
                    List<String> deletes = JSON.parseArray(authorityObject.getString("deletes"), String.class);
                    List<String> updates = JSON.parseArray(authorityObject.getString("updates"), String.class);
                    List<String> queries = JSON.parseArray(authorityObject.getString("queries"), String.class);
                    roleGrantedAuthority = new RoleGrantedAuthorityBO(roleId, roleName, menus, inserts, deletes, updates, queries);
                }
            }
            if (StringUtils.contains(roleGrantedAuthority.getAuthority(), ISystemConstant.ADMIN)) {
                LOG.debug("权限校验URI：{}，当前用户为最高管理员，有所有权限", requestURI);
                hasPermission = true;
                break;
            }
            // 放行权限
            if (hasPassPermission(contextPath, requestURI, roleGrantedAuthority, antPathMatcher)) {
                LOG.debug("权限校验URI：{}，有新增权限", requestURI);
                hasPermission = true;
                break;
            }
            if (hasMenuPermission(contextPath, requestURI, roleGrantedAuthority, antPathMatcher)) {
                LOG.debug("权限校验URI：{}，有菜单权限", requestURI);
                hasPermission = true;
                break;
            }
            if (!accessControlProperties.getRolePermission()) {
                LOG.debug("不校验URI的增、删、改、查权限");
                hasPermission = true;
                break;
            }
            // 新增权限
            if (hasInsertPermission(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, RoleGrantedAuthorityBO roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        if ((contextPath + ANT_PATH_BASE).equals(uri)) {
            return true;
        }
        List<String> passPaths = accessControlProperties.getPassPaths();
        for (String passPath : passPaths) {
            if (antPathMatcher.match(contextPath + passPath, uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 接口的菜单权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasMenuPermission(String contextPath, String uri, RoleGrantedAuthorityBO roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> menus = roleGrantedAuthority.getMenus();
        for (String menu : menus) {
            if (antPathMatcher.match(contextPath + menu, uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 接口的新增权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasInsertPermission(String contextPath, String uri, RoleGrantedAuthorityBO roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> inserts = roleGrantedAuthority.getInserts();
        for (String insert : inserts) {
            if (antPathMatcher.match(contextPath + insert, uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 接口的删除权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasDeletePermission(String contextPath, String uri, RoleGrantedAuthorityBO roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> deletes = roleGrantedAuthority.getDeletes();
        for (String delete : deletes) {
            if (antPathMatcher.match(contextPath + delete, uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 接口的修改权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasUpdatePermission(String contextPath, String uri, RoleGrantedAuthorityBO roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> updates = roleGrantedAuthority.getUpdates();
        for (String update : updates) {
            if (antPathMatcher.match(contextPath + update, uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 接口的查询权限
     *
     * @param uri
     * @param roleGrantedAuthority
     * @param antPathMatcher
     * @return
     */
    private boolean hasQueryPermission(String contextPath, String uri, RoleGrantedAuthorityBO roleGrantedAuthority, AntPathMatcher antPathMatcher) {
        List<String> queries = roleGrantedAuthority.getQueries();
        for (String query : queries) {
            if (antPathMatcher.match(contextPath + query, uri)) {
                return true;
            }
        }
        return false;
    }

}
