package de.effigenix.infrastructure.production.web;

import de.effigenix.domain.usermanagement.RoleName;
import de.effigenix.infrastructure.AbstractIntegrationTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;

import java.util.Set;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@DisplayName("GetRecipe Integration Tests")
class GetRecipeIntegrationTest extends AbstractIntegrationTest {

    private String adminToken;
    private String viewerToken;

    @BeforeEach
    void setUp() {
        String adminRoleId = createRole(RoleName.ADMIN, "Admin");
        String viewerRoleId = createRole(RoleName.PRODUCTION_WORKER, "Viewer");

        String adminId = createUser("recipe.admin", "recipe.admin@test.com", Set.of(adminRoleId), "BRANCH-01");
        String viewerId = createUser("recipe.viewer", "recipe.viewer@test.com", Set.of(viewerRoleId), "BRANCH-01");

        adminToken = generateToken(adminId, "recipe.admin", "RECIPE_WRITE,RECIPE_READ");
        viewerToken = generateToken(viewerId, "recipe.viewer", "USER_READ");
    }

    @Test
    @DisplayName("Rezept per ID abrufen → 200 mit vollständigen Daten")
    void getRecipe_existingId_returns200WithFullDetails() throws Exception {
        String recipeId = createRecipe();

        mockMvc.perform(get("/api/recipes/{id}", recipeId)
                        .header("Authorization", "Bearer " + adminToken))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(recipeId))
                .andExpect(jsonPath("$.name").value("Bratwurst"))
                .andExpect(jsonPath("$.version").value(1))
                .andExpect(jsonPath("$.ingredients").isArray())
                .andExpect(jsonPath("$.productionSteps").isArray());
    }

    @Test
    @DisplayName("Nicht existierendes Rezept → 404")
    void getRecipe_nonExistentId_returns404() throws Exception {
        mockMvc.perform(get("/api/recipes/{id}", "nonexistent-id")
                        .header("Authorization", "Bearer " + adminToken))
                .andExpect(status().isNotFound())
                .andExpect(jsonPath("$.code").value("RECIPE_NOT_FOUND"));
    }

    @Test
    @DisplayName("Rezept abrufen ohne RECIPE_READ → 403")
    void getRecipe_withoutPermission_returns403() throws Exception {
        mockMvc.perform(get("/api/recipes/{id}", "any-id")
                        .header("Authorization", "Bearer " + viewerToken))
                .andExpect(status().isForbidden());
    }

    @Test
    @DisplayName("Rezept abrufen ohne Token → 401")
    void getRecipe_withoutToken_returns401() throws Exception {
        mockMvc.perform(get("/api/recipes/{id}", "any-id"))
                .andExpect(status().isUnauthorized());
    }

    private String createRecipe() throws Exception {
        String json = """
                {
                    "name": "Bratwurst",
                    "version": 1,
                    "type": "FINISHED_PRODUCT",
                    "description": "Testrezept",
                    "yieldPercentage": 85,
                    "shelfLifeDays": 14,
                    "outputQuantity": "100",
                    "outputUom": "KILOGRAM",
                    "articleId": "article-123"
                }
                """;

        var result = mockMvc.perform(post("/api/recipes")
                        .header("Authorization", "Bearer " + adminToken)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(json))
                .andExpect(status().isCreated())
                .andReturn();

        return objectMapper.readTree(result.getResponse().getContentAsString()).get("id").asText();
    }
}
