package com.storycove.security;

import com.storycove.service.LibraryService;
import com.storycove.util.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    private final JwtUtil jwtUtil;
    private final LibraryService libraryService;

    public JwtAuthenticationFilter(JwtUtil jwtUtil, LibraryService libraryService) {
        this.jwtUtil = jwtUtil;
        this.libraryService = libraryService;
    }
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                  HttpServletResponse response, 
                                  FilterChain filterChain) throws ServletException, IOException {
        
        String token = null;
        
        // First try to get token from Authorization header
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            token = authHeader.substring(7);
        }
        
        // If no token in header, try to get from cookies
        if (token == null) {
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if ("token".equals(cookie.getName())) {
                        token = cookie.getValue();
                        break;
                    }
                }
            }
        }
        
        if (token != null && jwtUtil.validateToken(token) && !jwtUtil.isTokenExpired(token)) {
            String subject = jwtUtil.getSubjectFromToken(token);

            // Check if we need to switch libraries based on token's library ID
            try {
                String tokenLibraryId = jwtUtil.getLibraryIdFromToken(token);
                String currentLibraryId = libraryService.getCurrentLibraryId();

                // Switch library if token's library differs from current library
                // This handles cross-device library switching automatically
                if (tokenLibraryId != null && !tokenLibraryId.equals(currentLibraryId)) {
                    logger.info("Token library '{}' differs from current library '{}', switching libraries",
                            tokenLibraryId, currentLibraryId);
                    libraryService.switchToLibraryAfterAuthentication(tokenLibraryId);
                } else if (currentLibraryId == null && tokenLibraryId != null) {
                    // Handle case after backend restart where no library is active
                    logger.info("No active library, switching to token's library: {}", tokenLibraryId);
                    libraryService.switchToLibraryAfterAuthentication(tokenLibraryId);
                }
            } catch (Exception e) {
                logger.error("Failed to switch library from token: {}", e.getMessage());
                // Don't fail the request - authentication can still proceed
                // but user might see wrong library data until next login
            }

            if (subject != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UsernamePasswordAuthenticationToken authToken =
                    new UsernamePasswordAuthenticationToken(subject, null, new ArrayList<>());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        
        filterChain.doFilter(request, response);
    }
}