package demo;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;

/** The trap: a hand-built step-up factory WITHOUT @EnableMultiFactorAuthentication loses the first factor. */
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("stepupbare")
class MfaStepUpBareTest extends MfaTestSupport {

    @Autowired MockMvc mvc;
    @Autowired MfaTokenCatcher catcher;

    @BeforeAll
    static void clean() {
        new java.io.File("cap/13-stepup-bare-trap.txt").delete();
    }

    private static String where(MockHttpServletResponse r) {
        return r.getStatus() + (r.getRedirectedUrl() != null ? " -> " + r.getRedirectedUrl() : "");
    }

    @Test
    void secondLoginReplacesTheFirstFactor() throws Exception {
        String f = "13-stepup-bare-trap.txt";
        var login = mvc.perform(formLogin().user("alice").password("pw")).andReturn();
        MockHttpSession session = (MockHttpSession) login.getRequest().getSession();
        say(f, "after password login         : " + authorities(session));
        mvc.perform(post("/ott/generate").param("username", "alice").session(session).with(csrf()));
        var ott = mvc.perform(post("/login/ott").param("token", catcher.last()).session(session).with(csrf())).andReturn();
        MockHttpSession after = (MockHttpSession) ott.getRequest().getSession();
        say(f, "after valid token login      : " + authorities(after));
        var admin = mvc.perform(get("/admin/panel").session(after).accept("text/html")).andReturn().getResponse();
        say(f, "GET /admin/panel             : " + where(admin));
        assertThat(authorities(after)).doesNotContain("FACTOR_PASSWORD");
    }
}
