package org.apereo.cas.authentication.mfa;

import org.apereo.cas.authentication.MultifactorAuthenticationUtils;
import org.apereo.cas.util.RegexUtils;
import org.apereo.cas.util.spring.ApplicationContextProvider;

import lombok.val;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.binding.expression.support.LiteralExpression;
import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.webflow.context.servlet.ServletExternalContext;
import org.springframework.webflow.engine.Transition;
import org.springframework.webflow.engine.support.DefaultTargetStateResolver;
import org.springframework.webflow.engine.support.DefaultTransitionCriteria;
import org.springframework.webflow.test.MockRequestContext;

import java.util.List;
import java.util.Optional;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

/**
 * This is {@link MultifactorAuthenticationUtilsTests}.
 *
 * @author Misagh Moayyed
 * @since 6.2.0
 */
@DirtiesContext
@SpringBootTest(classes = AopAutoConfiguration.class)
@Tag("MFA")
public class MultifactorAuthenticationUtilsTests {
    @Autowired
    private ConfigurableApplicationContext applicationContext;

    @Test
    public void verifyResolveByAttribute() {
        val context = new MockRequestContext();
        val request = new MockHttpServletRequest();
        val response = new MockHttpServletResponse();
        context.setExternalContext(new ServletExternalContext(new MockServletContext(), request, response));

        ApplicationContextProvider.holdApplicationContext(applicationContext);
        val provider = TestMultifactorAuthenticationProvider.registerProviderIntoApplicationContext(applicationContext);
        assertTrue(MultifactorAuthenticationUtils.getMultifactorAuthenticationProviderFromApplicationContext(provider.getId()).isPresent());

        val targetResolver = new DefaultTargetStateResolver(TestMultifactorAuthenticationProvider.ID);
        val transition = new Transition(new DefaultTransitionCriteria(
            new LiteralExpression(TestMultifactorAuthenticationProvider.ID)), targetResolver);
        context.getRootFlow().getGlobalTransitionSet().add(transition);

        var result = MultifactorAuthenticationUtils.resolveEventViaMultivaluedAttribute(MultifactorAuthenticationTestUtils.getPrincipal("casuser"),
            List.of("mfa-value"), MultifactorAuthenticationTestUtils.getRegisteredService(),
            Optional.of(context), provider, s -> RegexUtils.find("mfa-.+", s));
        assertNotNull(result);
        assertFalse(result.isEmpty());
    }

    @Test
    public void verifyProviderByService() {
        ApplicationContextProvider.holdApplicationContext(applicationContext);
        val provider = TestMultifactorAuthenticationProvider.registerProviderIntoApplicationContext(applicationContext);
        assertTrue(MultifactorAuthenticationUtils.getMultifactorAuthenticationProviderFromApplicationContext(provider.getId()).isPresent());

        val registeredService = MultifactorAuthenticationTestUtils.getRegisteredService();
        when(registeredService.getMultifactorPolicy().getMultifactorAuthenticationProviders()).thenReturn(Set.of("mfa-other"));
        var result = MultifactorAuthenticationUtils.getMultifactorAuthenticationProviderForService(registeredService);
        assertNotNull(result);
        assertTrue(result.isEmpty());

        when(registeredService.getMultifactorPolicy().getMultifactorAuthenticationProviders()).thenReturn(Set.of(provider.getId()));
        result = MultifactorAuthenticationUtils.getMultifactorAuthenticationProviderForService(registeredService);
        assertNotNull(result);
        assertFalse(result.isEmpty());
    }
}

@@ -2700,33 +2700,33 @@
 on);%0A%0A        va
-r
+l
  result = Multif
@@ -3042,32 +3042,32 @@
 otNull(result);%0A
-
         assertFa
@@ -3096,16 +3096,1366 @@
 %0A    %7D%0A%0A
+    @Test%0A    public void verifyMultivaluedAttrs() %7B%0A        ApplicationContextProvider.holdApplicationContext(applicationContext);%0A        val provider = TestMultifactorAuthenticationProvider.registerProviderIntoApplicationContext(applicationContext);%0A%0A        val context = new MockRequestContext();%0A        val request = new MockHttpServletRequest();%0A        val response = new MockHttpServletResponse();%0A        context.setExternalContext(new ServletExternalContext(new MockServletContext(), request, response));%0A%0A        var result = MultifactorAuthenticationUtils.resolveEventViaMultivaluedAttribute(MultifactorAuthenticationTestUtils.getPrincipal(%22casuser%22),%0A            List.of(%22some-value%22), MultifactorAuthenticationTestUtils.getRegisteredService(), Optional.of(context), provider,%0A            s -%3E %7B%0A                throw new RuntimeException(%22Bad Predicate%22);%0A            %7D);%0A        assertNotNull(result);%0A        assertTrue(result.isEmpty());%0A%0A        result = MultifactorAuthenticationUtils.resolveEventViaMultivaluedAttribute(MultifactorAuthenticationTestUtils.getPrincipal(%22casuser%22),%0A            %22some-value%22, MultifactorAuthenticationTestUtils.getRegisteredService(), Optional.of(context), provider,%0A            s -%3E %7B%0A                throw new RuntimeException(%22Bad Predicate%22);%0A            %7D);%0A        assertNull(result);%0A    %7D%0A%0A
     @Tes

add tests