package com.smartoffice;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.Test;
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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.time.Instant;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class ApiFlowTest {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void login_returns_token_and_user() throws Exception {
        JsonNode response = login("admin", "admin123");
        assertThat(response.path("data").path("token").asText()).isNotBlank();
        assertThat(response.path("data").path("user").path("username").asText()).isEqualTo("admin");
    }

    @Test
    void check_in_creates_attendance_record() throws Exception {
        String token = tokenFor("employee", "employee123");
        ObjectNode payload = objectMapper.createObjectNode();
        payload.put("location", "HQ");

        mockMvc.perform(post("/api/v1/attendance/check-in")
                        .contentType(MediaType.APPLICATION_JSON)
                        .header("Authorization", "Bearer " + token)
                        .content(objectMapper.writeValueAsString(payload)))
                .andExpect(status().isOk());
    }

    @Test
    void manager_can_approve_leave_request() throws Exception {
        String employeeToken = tokenFor("employee", "employee123");
        ObjectNode leaveRequest = objectMapper.createObjectNode();
        Instant start = Instant.now().plusSeconds(3600);
        leaveRequest.put("type", "ANNUAL");
        leaveRequest.put("startTime", start.toString());
        leaveRequest.put("endTime", start.plusSeconds(3600).toString());
        leaveRequest.put("reason", "Family matters");

        String createdResponse = mockMvc.perform(post("/api/v1/leave-requests")
                        .contentType(MediaType.APPLICATION_JSON)
                        .header("Authorization", "Bearer " + employeeToken)
                        .content(objectMapper.writeValueAsString(leaveRequest)))
                .andExpect(status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString();

        JsonNode createdJson = objectMapper.readTree(createdResponse);
        Long leaveId = createdJson.path("data").path("id").asLong();

        String managerToken = tokenFor("manager", "manager123");
        ObjectNode decision = objectMapper.createObjectNode();
        decision.put("note", "Approved");

        String approvedResponse = mockMvc.perform(post("/api/v1/leave-requests/" + leaveId + "/approve")
                        .contentType(MediaType.APPLICATION_JSON)
                        .header("Authorization", "Bearer " + managerToken)
                        .content(objectMapper.writeValueAsString(decision)))
                .andExpect(status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString();

        JsonNode approvedJson = objectMapper.readTree(approvedResponse);
        assertThat(approvedJson.path("data").path("status").asText()).isEqualTo("APPROVED");
    }

    private String tokenFor(String username, String password) throws Exception {
        return login(username, password).path("data").path("token").asText();
    }

    private JsonNode login(String username, String password) throws Exception {
        ObjectNode payload = objectMapper.createObjectNode();
        payload.put("username", username);
        payload.put("password", password);

        String response = mockMvc.perform(post("/api/v1/auth/login")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(payload)))
                .andExpect(status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString();

        return objectMapper.readTree(response);
    }
}
