package cn.stylefeng.guns.core.security;

import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.auth.api.AuthServiceApi;
import cn.stylefeng.roses.kernel.auth.api.PermissionServiceApi;
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
import cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum;
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
import cn.stylefeng.roses.kernel.auth.api.pojo.payload.DefaultJwtPayload;
import cn.stylefeng.roses.kernel.rule.util.AntPathMatcherUtil;
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.ResourceDefinition;
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.ResourceUrlParam;
import cn.stylefeng.roses.kernel.sys.api.ResourceServiceApi;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
@Slf4j
public class TokenAndPermissionInterceptor implements HandlerInterceptor {

    @Resource
    private ResourceServiceApi resourceServiceApi;

    @Resource
    private AuthServiceApi authServiceApi;

    @Resource
    private SessionManagerApi sessionManagerApi;

    @Resource
    private PermissionServiceApi permissionServiceApi;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

        String requestURI = request.getRequestURI();
        requestURI = requestURI.replaceAll("/+", "/");

        Boolean noneSecurityFlag = AntPathMatcherUtil.getAntMatchFLag(requestURI, request.getContextPath(),
                AuthConfigExpander.getNoneSecurityConfig());
        if (noneSecurityFlag) {
            return true;
        }

        String token = null;
        try {
            token = LoginContext.me().getToken();
        } catch (Exception e) {

        }

        if (StrUtil.isNotBlank(token)) {
            DefaultJwtPayload defaultJwtPayload = null;
            try {
                defaultJwtPayload = authServiceApi.validateToken(token);
            } catch (AuthException authException) {
                if (AuthExceptionEnum.AUTH_EXPIRED_ERROR.getErrorCode().equals(authException.getErrorCode())) {
                    throw authException;
                }
            }

            sessionManagerApi.refreshSession(token);

            if (defaultJwtPayload != null && !sessionManagerApi.haveSession(token)) {
                authServiceApi.createNewLoginInfo(token, defaultJwtPayload);
            }
        }

        ResourceUrlParam resourceUrlParam = new ResourceUrlParam();
        resourceUrlParam.setUrl(requestURI);
        ResourceDefinition resourceDefinition = resourceServiceApi.getResourceByUrl(resourceUrlParam);

        if (resourceDefinition == null) {
            throw new AuthException(AuthExceptionEnum.CANT_REQUEST_UN_OPEN_API, requestURI);
        }

        if (resourceDefinition.getRequiredLoginFlag()) {

            if (StrUtil.isEmpty(token)) {
                throw new AuthException(AuthExceptionEnum.TOKEN_GET_ERROR);
            }

            authServiceApi.checkAuth(token, requestURI);
        }

        if (resourceDefinition.getRequiredPermissionFlag()) {

            if (StrUtil.isEmpty(token)) {
                throw new AuthException(AuthExceptionEnum.TOKEN_GET_ERROR);
            }

            permissionServiceApi.checkPermission(token, requestURI);
        }

        return true;
    }

}
