package app.mealsmadeeasy.api.recipe;

import app.mealsmadeeasy.api.MinIOTestsExtension;
import app.mealsmadeeasy.api.PostgresTestsExtension;
import app.mealsmadeeasy.api.auth.AuthService;
import app.mealsmadeeasy.api.auth.LoginException;
import app.mealsmadeeasy.api.recipe.view.RecipeDraftView;
import app.mealsmadeeasy.api.user.User;
import app.mealsmadeeasy.api.user.UserCreateException;
import app.mealsmadeeasy.api.user.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.MimeTypeUtils;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@ExtendWith({ PostgresTestsExtension.class, MinIOTestsExtension.class })
@AutoConfigureMockMvc
public class RecipeDraftsControllerAiIntegrationTests {

    private static final String TEST_PASSWORD = "test";

    @Autowired
    private UserService userService;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private AuthService authService;

    @Autowired
    private ObjectMapper objectMapper;

    private User seedUser() {
        final String uuid = UUID.randomUUID().toString();
        try {
            return this.userService.createUser(uuid, uuid + "@test.com", "test");
        } catch (UserCreateException e) {
            throw new RuntimeException(e);
        }
    }

    private String getAccessToken(User user) throws LoginException {
        return this.authService.login(user.getUsername(), TEST_PASSWORD)
                .getAccessToken()
                .getToken();
    }

    @Test
    public void pollAiDraft_returnsDraft() throws Exception {
        final User owner = this.seedUser();
        final MockMultipartFile sourceFile = new MockMultipartFile(
                "sourceFile",
                "recipe.jpeg",
                MimeTypeUtils.IMAGE_JPEG_VALUE,
                this.getClass().getResourceAsStream("/recipe.jpeg")
        );
        final MvcResult multipartResult = this.mockMvc.perform(
                        multipart("/recipe-drafts/ai")
                                .file(sourceFile)
                                .param("sourceFileName", sourceFile.getOriginalFilename())
                                .header("Authorization", "Bearer " + this.getAccessToken(owner))
                )
                .andExpect(status().isCreated())
                .andReturn();

        final String rawContent = multipartResult.getResponse().getContentAsString();
        final RecipeDraftView recipeDraftView = this.objectMapper.readValue(rawContent, RecipeDraftView.class);

        await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
            this.mockMvc.perform(
                            get("/recipe-drafts/{id}", recipeDraftView.id())
                                    .header("Authorization", "Bearer " + this.getAccessToken(owner))
                    )
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("$.state", is(RecipeDraft.State.ENTER_DATA.toString())));
        });
    }
}
