package cn.skcks.matrix.v2.config;

import cn.skcks.matrix.v2.auth.claims.ClaimResolver;
import cn.skcks.matrix.v2.interceptor.AuthorizationInterceptor;
import cn.skcks.matrix.v2.model.jwt.dto.Claims;
import cn.skcks.matrix.v2.services.auth.AuthService;
import cn.skcks.matrix.v2.services.casbin.CasbinService;
import cn.skcks.matrix.v2.services.casbin.Permission;
import cn.skcks.matrix.v2.services.jwt.JwtService;
import cn.skcks.matrix.v2.utils.json.JsonResponse;
import cn.skcks.matrix.v2.utils.json.ResponseStatus;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

@Slf4j
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
    private final AuthorizationInterceptor authorizationInterceptor;
    private final ObjectMapper objectMapper;
    private final JwtService jwtService;
    private final AuthService authService;

    private final CasbinService casbinService;
    private final ClaimResolver claimResolver;

    private final static JsonResponse<String> NO_LOGIN = JsonResponse.build( ResponseStatus.UNAUTHORIZED,"未登录");
    private final static JsonResponse<String> TOKEN_EXPIRE = JsonResponse.build(ResponseStatus.UNAUTHORIZED,"认证失效 请重新登录");

    private final static JsonResponse<String> NO_PERMISSION = JsonResponse.build(ResponseStatus.FORBIDDEN,"无权访问");

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(claimResolver);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加请求 权限校验 拦截器
        authorizationInterceptor.addAuthHandler(this::auth);

        registry.addInterceptor(authorizationInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/error/**", "/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**");
    }

    private void writeResponse(HttpServletResponse response, int status, Object data) throws IOException {
        response.setStatus(status);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        objectMapper.writeValue(response.getWriter(), data);
    }

    private String getToken(HttpServletRequest request) {
        return Optional.ofNullable(request.getHeader("token")).orElseGet(() -> {
            if (request.getCookies() != null) {
                for (Cookie cookie : request.getCookies()) {
                    if (cookie.getName().equals("token")) {
                        return cookie.getValue();
                    }
                }
            }
            return null;
        });
    }

    private String getSystem(HttpServletRequest request) {
        return Optional.ofNullable(request.getHeader("system")).orElseGet(() -> {
            if (request.getCookies() != null) {
                for (Cookie cookie : request.getCookies()) {
                    if (cookie.getName().equals("system")) {
                        return cookie.getValue();
                    }
                }
            }
            return CasbinService.DEFAULT_SYSTEM;
        });
    }

    private boolean auth(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = getToken(request);
        log.info("token => {}", token);

        if (token == null) {
            writeResponse(response, NO_LOGIN.getCode(), NO_LOGIN);
            return false;
        }

        Claims claims = jwtService.parseToken(token);
        request.setAttribute("claims", claims);
        log.info("[解析的令牌信息] {}", claims);
        if (claims == null) {
            log.info("[认证失败] 无效 token => {}", token);
            writeResponse(response, NO_LOGIN.getCode(), NO_LOGIN);
            return false;
        }

        if (!authService.validateToken(claims, token)) {
            writeResponse(response, TOKEN_EXPIRE.getCode(), TOKEN_EXPIRE);
            return false;
        }


        String system = getSystem(request);
        List<Permission> permissions = casbinService.getUserPermission(claims.getUserId(),system);
        log.debug("用户 {} 拥有的权限数量 {}", claims.getUserId(),permissions.size());
        for (Permission permission : permissions) {
            log.info("permission {}", permission);
            if(casbinService.enforce(permission.getName(),system,request.getRequestURI(),request.getMethod())){
                return true;
            }
        }

        writeResponse(response, NO_PERMISSION.getCode(), NO_PERMISSION);
        return false;
    }
}
