package dev.lions.unionflow.client.exception;

import jakarta.faces.FacesException;
import jakarta.faces.application.NavigationHandler;
import jakarta.faces.application.ViewExpiredException;
import jakarta.faces.context.ExceptionHandler;
import jakarta.faces.context.ExceptionHandlerWrapper;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.ExceptionQueuedEvent;
import jakarta.faces.event.ExceptionQueuedEventContext;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {
    
    private static final Logger LOG = Logger.getLogger(ViewExpiredExceptionHandler.class.getName());
    private ExceptionHandler wrapped;
    
    public ViewExpiredExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }
    
    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }
    
    @Override
    public void handle() throws FacesException {
        Iterator<ExceptionQueuedEvent> iterator = getUnhandledExceptionQueuedEvents().iterator();
        
        while (iterator.hasNext()) {
            ExceptionQueuedEvent event = iterator.next();
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
            Throwable throwable = context.getException();
            
            if (throwable instanceof ViewExpiredException) {
                ViewExpiredException vee = (ViewExpiredException) throwable;
                FacesContext facesContext = FacesContext.getCurrentInstance();
                
                try {
                    LOG.log(Level.INFO, "ViewExpiredException interceptée pour la vue: {0}", vee.getViewId());
                    
                    // Vérifier que FacesContext et ExternalContext sont disponibles
                    if (facesContext != null && facesContext.getExternalContext() != null) {
                        // Stocker l'URL demandée pour redirection après connexion si possible
                        String originalURL = vee.getViewId();
                        try {
                            if (facesContext.getExternalContext().getSessionMap() != null) {
                                facesContext.getExternalContext().getSessionMap().put("redirectURL", originalURL);
                            }
                        } catch (Exception e) {
                            LOG.log(Level.WARNING, "Impossible de stocker l'URL de redirection: {0}", e.getMessage());
                        }
                        
                        // Rediriger vers la page de login avec paramètre expired
                        try {
                            String redirectURL = "/pages/public/login.xhtml?expired=true";
                            facesContext.getExternalContext().redirect(
                                facesContext.getExternalContext().getRequestContextPath() + redirectURL
                            );
                            facesContext.responseComplete();
                        } catch (Exception e) {
                            LOG.log(Level.SEVERE, "Erreur lors de la redirection: {0}", e.getMessage());
                            // Fallback: essayer une redirection simple
                            try {
                                facesContext.getExternalContext().redirect("/pages/public/login.xhtml");
                                facesContext.responseComplete();
                            } catch (Exception fallbackException) {
                                LOG.log(Level.SEVERE, "Impossible de rediriger vers login: {0}", fallbackException.getMessage());
                            }
                        }
                    }
                } catch (Exception e) {
                    LOG.log(Level.SEVERE, "Erreur dans ViewExpiredExceptionHandler: {0}", e.getMessage());
                } finally {
                    iterator.remove();
                }
            }
        }
        
        // Laisser le parent gérer les autres exceptions
        getWrapped().handle();
    }
}