/*
 * File: src/main/java/reports/interceptor/JwtInterceptor.java
 * Description: This interceptor is responsible for handling JWT authentication
 * in incoming HTTP requests. It checks for the presence and validity of the
 * JWT token in the Authorization header before allowing access to protected resources.
 *
 * Key Components:
 *
 * - **@Component**: Marks this class as a Spring component, allowing it to be
 *   detected and registered as a bean in the application context.
 *
 * - **HandlerInterceptor**: This interface provides methods to intercept HTTP
 *   requests, allowing for pre-processing (before the request is handled) and
 *   post-processing (after the request has been handled).
 *
 * - **JwtUtils**: A utility class used for managing JWT token validation and
 *   expiration checks.
 *
 * - **ObjectMapper**: A Jackson utility for converting Java objects to and from
 *   JSON format.
*/

package com.nebula.erp.reports.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nebula.erp.reports.utility.ApiResponseStructure;
import com.nebula.erp.reports.utility.JwtUtils;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtils jwtUtils;

    private final ObjectMapper objectMapper = new ObjectMapper(); // Jackson ObjectMapper for JSON conversion

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        // Extract the Authorization header directly from the request
        String authorizationHeader = request.getHeader("Authorization");

        // Check if the Authorization header is missing
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Authorization token is missing.");
            return false;
        }

        // Extract the token from the Authorization header
        String token = authorizationHeader.substring(7); // Remove the "Bearer " prefix

        try {
            // Check if the token is expired
            if (jwtUtils.isTokenExpired(token)) {
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Token expired.");
                return false;
            }

        } catch (ExpiredJwtException e) {
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Token expired at " + e.getClaims().getExpiration());
            return false;
        } catch (Exception e) {
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Invalid token.");
            return false;
        }

        return true; // Allow the request to proceed
    }

    private void sendErrorResponse(HttpServletResponse response, int statusCode, String message) throws IOException {
        response.setStatus(statusCode);
        response.setContentType("application/json");

        // Creating an ApiResponseStructure object
        ApiResponseStructure<Void> apiResponse = new ApiResponseStructure<>(
                "Failure", statusCode, message, null);

        // Convert ApiResponseStructure object to JSON string
        String jsonResponse = objectMapper.writeValueAsString(apiResponse);

        // Write the JSON response to the response body
        response.getWriter().write(jsonResponse);
    }
}
