package cn.novalon.gym.manage.gateway.filter;

import cn.novalon.gym.manage.gateway.service.PermissionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

@Component
public class RbacAuthorizationFilter extends AbstractGatewayFilterFactory<RbacAuthorizationFilter.Config> {

    private static final Logger logger = LoggerFactory.getLogger(RbacAuthorizationFilter.class);
    
    private final PermissionService permissionService;

    public RbacAuthorizationFilter(PermissionService permissionService) {
        super(Config.class);
        this.permissionService = permissionService;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            String method = request.getMethod().name();

            if (isPublicPath(path)) {
                logger.debug("Public path access: {}", path);
                return chain.filter(exchange);
            }

            String userIdHeader = request.getHeaders().getFirst("X-User-Id");
            if (userIdHeader == null || userIdHeader.isEmpty()) {
                logger.warn("Missing X-User-Id header for path: {}", path);
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            Long userId;
            try {
                userId = Long.parseLong(userIdHeader);
            } catch (NumberFormatException e) {
                logger.error("Invalid X-User-Id header: {}", userIdHeader, e);
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            if (!permissionService.hasPermission(userId, path, method)) {
                logger.warn("Permission denied for userId: {}, path: {}, method: {}", userId, path, method);
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                return exchange.getResponse().setComplete();
            }

            logger.debug("Permission granted for userId: {}, path: {}, method: {}", userId, path, method);
            return chain.filter(exchange);
        };
    }

    private boolean isPublicPath(String path) {
        return path.startsWith("/api/auth/") ||
               path.equals("/actuator/health") ||
               path.startsWith("/actuator/info") ||
               path.startsWith("/api/checkIn/");
    }

    public static class Config {
    }
}
