package com.inspect.common.security.auth;

import com.inspect.base.core.exception.auth.NotLoginException;
import com.inspect.base.core.exception.auth.NotPermissionException;
import com.inspect.base.core.exception.auth.NotRoleException;
import com.inspect.base.core.utils.SpringUtils;
import com.inspect.base.core.utils.StringUtils;
import com.inspect.common.security.annotation.Logical;
import com.inspect.common.security.annotation.RequiresLogin;
import com.inspect.common.security.annotation.RequiresPermissions;
import com.inspect.common.security.annotation.RequiresRoles;
import com.inspect.common.security.service.TokenService;
import com.inspect.common.security.utils.SecurityUtils;
import com.inspect.system.base.model.LoginUser;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.springframework.util.PatternMatchUtils;

public class AuthLogic {
    private static final String ALL_PERMISSION = "*:*:*";
    private static final String SUPER_ADMIN = "admin";
    public TokenService tokenService = SpringUtils.getBean(TokenService.class);

    public void logout() {
        String token = SecurityUtils.getToken();
        if (token != null) {
            this.logoutByToken(token);
        }
    }

    public void logoutByToken(String token) {
        this.tokenService.delLoginUser(token);
    }

    public void checkLogin() {
        this.getLoginUser();
    }

    public LoginUser getLoginUser() {
        String token = SecurityUtils.getToken();
        if (token == null) {
            throw new NotLoginException("未提供token");
        } else {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            if (loginUser == null) {
                throw new NotLoginException("无效的token");
            } else {
                return loginUser;
            }
        }
    }

    public LoginUser getLoginUser(String token) {
        return this.tokenService.getLoginUser(token);
    }

    public void verifyLoginUserExpire(LoginUser loginUser) {
        this.tokenService.verifyToken(loginUser);
    }

    public boolean hasPermission(String permission) {
        return this.hasPermission(this.getPermissionList(), permission);
    }

    public void checkPermission(String permission) {
        if (!this.hasPermission(this.getPermissionList(), permission)) {
            throw new NotPermissionException(permission);
        }
    }

    public void checkPermission(RequiresPermissions requiresPermissions) {
        if (requiresPermissions.logical() == Logical.AND) {
            this.checkPermissionAnd(requiresPermissions.value());
        } else {
            this.checkPermiOr(requiresPermissions.value());
        }

    }

    public void checkPermissionAnd(String... permissions) {
        Set<String> permissionList = this.getPermissionList();
        String[] var3 = permissions;
        int var4 = permissions.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            String permission = var3[var5];
            if (!this.hasPermission(permissionList, permission)) {
                throw new NotPermissionException(permission);
            }
        }

    }

    public void checkPermiOr(String... permissions) {
        Set<String> permissionList = this.getPermissionList();
        String[] var3 = permissions;
        int var4 = permissions.length;

        for (int var5 = 0; var5 < var4; ++var5) {
            String permission = var3[var5];
            if (this.hasPermission(permissionList, permission)) {
                return;
            }
        }

        if (permissions.length > 0) {
            throw new NotPermissionException(permissions);
        }
    }

    public boolean hasRole(String role) {
        return this.hasRole(this.getRoleList(), role);
    }

    public void checkRole(String role) {
        if (!this.hasRole(role)) {
            throw new NotRoleException(role);
        }
    }

    public void checkRole(RequiresRoles requiresRoles) {
        if (requiresRoles.logical() == Logical.AND) {
            this.checkRoleAnd(requiresRoles.value());
        } else {
            this.checkRoleOr(requiresRoles.value());
        }

    }

    public void checkRoleAnd(String... roles) {
        Set<String> roleList = this.getRoleList();

        for (String role : roles) {
            if (!this.hasRole(roleList, role)) {
                throw new NotRoleException(role);
            }
        }

    }

    public void checkRoleOr(String... roles) {
        Set<String> roleList = this.getRoleList();
        for (String role : roles) {
            if (this.hasRole(roleList, role)) {
                return;
            }
        }

        if (roles.length > 0) {
            throw new NotRoleException(roles);
        }
    }

    public void checkByAnnotation(RequiresLogin at) {
        this.checkLogin();
    }

    public void checkByAnnotation(RequiresRoles at) {
        String[] roleArray = at.value();
        if (at.logical() == Logical.AND) {
            this.checkRoleAnd(roleArray);
        } else {
            this.checkRoleOr(roleArray);
        }

    }

    public void checkByAnnotation(RequiresPermissions at) {
        String[] permissionArray = at.value();
        if (at.logical() == Logical.AND) {
            this.checkPermissionAnd(permissionArray);
        } else {
            this.checkPermiOr(permissionArray);
        }

    }

    public Set<String> getRoleList() {
        try {
            LoginUser loginUser = this.getLoginUser();
            return loginUser.getRoles();
        } catch (Exception e) {
            return new HashSet<>();
        }
    }

    public Set<String> getPermissionList() {
        try {
            LoginUser loginUser = this.getLoginUser();
            return loginUser.getPermissions();
        } catch (Exception e) {
            return new HashSet<>();
        }
    }

    public boolean hasPermission(Collection<String> authorities, String permission) {
        return authorities.stream().filter(StringUtils::hasText).anyMatch((x) -> {
            return ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(x, permission);
        });
    }

    public boolean hasRole(Collection<String> roles, String role) {
        return roles.stream().filter(StringUtils::hasText).anyMatch((x) -> {
            return SUPER_ADMIN.contains(x) || PatternMatchUtils.simpleMatch(x, role);
        });
    }
}
