package dev.lions.unionflow.client.el;

import jakarta.el.ELContext;
import jakarta.el.ELResolver;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.CDI;
import java.util.Set;

/**
 * ELResolver personnalisé pour intégrer Quarkus Arc avec MyFaces JSF.
 * 
 * <p>Ce resolver permet à MyFaces d'utiliser les beans CDI gérés par Quarkus Arc
 * dans les expressions EL (#{bean.property}).
 * 
 * <p>Quarkus Arc ne supporte pas la méthode BeanManager.getELResolver(),
 * donc nous devons créer notre propre resolver qui utilise Arc directement.
 *
 * @author UnionFlow Team
 * @version 1.0
 */
public class QuarkusArcELResolver extends ELResolver {

    /**
     * Obtient le BeanManager via CDI.current().
     * Cette méthode est thread-safe et fonctionne avec Quarkus Arc.
     */
    private BeanManager getBeanManager() {
        try {
            CDI<Object> cdi = CDI.current();
            return cdi.getBeanManager();
        } catch (IllegalStateException e) {
            // Si CDI n'est pas disponible, retourner null
            return null;
        }
    }

    @Override
    public Object getValue(ELContext context, Object base, Object property) {
        BeanManager beanManager = getBeanManager();
        if (beanManager == null) {
            return null;
        }
        
        // Si base est null, on cherche un bean CDI avec le nom 'property'
        if (base == null && property != null) {
            String beanName = property.toString();
            
            // Chercher le bean par nom
            Set<Bean<?>> beans = beanManager.getBeans(beanName);
            if (!beans.isEmpty()) {
                Bean<?> bean = beans.iterator().next();
                Object beanInstance = beanManager.getReference(bean, bean.getBeanClass(), 
                    beanManager.createCreationalContext(bean));
                
                context.setPropertyResolved(true);
                return beanInstance;
            }
            
            // Chercher le bean par type (si le nom correspond à un nom de classe simple)
            try {
                Class<?> beanClass = Class.forName(beanName);
                Set<Bean<?>> typeBeans = beanManager.getBeans(beanClass);
                if (!typeBeans.isEmpty()) {
                    Bean<?> bean = typeBeans.iterator().next();
                    Object beanInstance = beanManager.getReference(bean, bean.getBeanClass(),
                        beanManager.createCreationalContext(bean));
                    
                    context.setPropertyResolved(true);
                    return beanInstance;
                }
            } catch (ClassNotFoundException e) {
                // Ignorer, ce n'est pas un nom de classe valide
            }
        }
        
        // Si base n'est pas null, on essaie d'accéder à une propriété
        if (base != null && property != null) {
            // Utiliser le resolver par défaut pour les propriétés
            return null;
        }
        
        return null;
    }

    @Override
    public Class<?> getType(ELContext context, Object base, Object property) {
        BeanManager beanManager = getBeanManager();
        if (beanManager == null) {
            return null;
        }
        
        if (base == null && property != null) {
            String beanName = property.toString();
            Set<Bean<?>> beans = beanManager.getBeans(beanName);
            if (!beans.isEmpty()) {
                Bean<?> bean = beans.iterator().next();
                context.setPropertyResolved(true);
                return bean.getBeanClass();
            }
        }
        return null;
    }

    @Override
    public void setValue(ELContext context, Object base, Object property, Object value) {
        // Les beans CDI sont généralement en lecture seule via EL
        // Cette méthode peut être laissée vide ou implémentée selon les besoins
    }

    @Override
    public boolean isReadOnly(ELContext context, Object base, Object property) {
        BeanManager beanManager = getBeanManager();
        if (beanManager == null) {
            return false;
        }
        
        if (base == null && property != null) {
            String beanName = property.toString();
            Set<Bean<?>> beans = beanManager.getBeans(beanName);
            if (!beans.isEmpty()) {
                context.setPropertyResolved(true);
                // Les beans CDI sont généralement en lecture seule via EL
                return true;
            }
        }
        return false;
    }

    @Override
    public Class<?> getCommonPropertyType(ELContext context, Object base) {
        if (base == null) {
            return Object.class;
        }
        return null;
    }
}

