package ua.tqs;


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 org.springframework.transaction.annotation.Transactional;


import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest(classes = ZeroMonosApplication.class)
@AutoConfigureMockMvc
@Transactional
class BookingsControllerTest {

    @Autowired
    private MockMvc mock;
    

    //test that when a booking is created, it returns a token and state is RECEIVED
    @Test
    void whenPOSTBooking_thenReturnsTokenAndReceivedState() throws Exception {
        String json = """
            {
              "citizenName": "Tomas Carvalho",
              "citizenPhone": "912345678",
              "municipality": "Águeda",
              "description": "Old washing machine"
            }
        """;

        mock.perform(post("/citizen").contentType(MediaType.APPLICATION_JSON).content(json))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.token").exists())
            .andExpect(jsonPath("$.state").value("RECEIVED"));
    }

    //test that we can get all bookings
    @Test
    void whenGetAllBookings_thenReturnList() throws Exception {
        String json = """
            {
              "citizenName": "Ana Silva",
              "citizenPhone": "911234567",
              "municipality": "Vila Nova de Gaia",
              "description": "TV"
            }
        """;

        mock.perform(post("/citizen").contentType(MediaType.APPLICATION_JSON).content(json))
            .andExpect(status().isOk());

        mock.perform(get("/staff/bookings")).andExpect(status().isOk());
    }

    //test that we can get booking details by token
    @Test
    void whenGetBookingByToken_thenReturnBooking() throws Exception {
        String json = """
            {
              "citizenName": "Alice Loureiro",
              "citizenPhone": "933456789",
              "municipality": "Aguiar da Beira",
              "description": "Old fridge"
            }
        """;

        String response = mock.perform(post("/citizen").contentType(MediaType.APPLICATION_JSON).content(json))
                            .andReturn().getResponse().getContentAsString();

        //get token
        String token = response.split("\"token\":\"")[1].split("\"")[0];

        //fetch it by token
        mock.perform(get("/staff/bookings/" + token))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.citizenName").value("Alice Loureiro"))
            .andExpect(jsonPath("$.municipality").value("Aguiar da Beira"));
    }


    @Test
    void whenUpdateState_stateUpdates() throws Exception {
        String json = """
            {
              "citizenName": "Paulo Silva",
              "citizenPhone": "913876234",
              "municipality": "Vila do Conde",
              "description": "Old Microwave"
            }
        """;

        String response = mock.perform(post("/citizen").contentType(MediaType.APPLICATION_JSON).content(json))
                            .andReturn().getResponse().getContentAsString();

        String token = response.split("\"token\":\"")[1].split("\"")[0];

        //update its state to ASSIGNED
        mock.perform(put("/staff/bookings/" + token + "/state").content("\"ASSIGNED\"").contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.state").value("ASSIGNED"));
    }

    @Test
    void whenUpdateState_thenHistoryUpdates() throws Exception {
        String json = """
            {
              "citizenName": "Bruno José",
              "citizenPhone": "919232454",
              "municipality": "Santarém",
              "description": "Mattress"
            }
        """;

        String response = mock.perform(post("/citizen").contentType(MediaType.APPLICATION_JSON).content(json))
                            .andReturn().getResponse().getContentAsString();

        String token = response.split("\"token\":\"")[1].split("\"")[0];

        //update its state to ASSIGNED
        mock.perform(put("/staff/bookings/" + token + "/state").content("\"ASSIGNED\"").contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk());

        String historyResponse = mock.perform(get("/staff/bookings/" + token + "/history"))
            .andExpect(status().isOk())
            .andReturn()
            .getResponse()
            .getContentAsString();

         assertTrue(historyResponse.contains("RECEIVED"), "State history should contain RECEIVED");
    assertTrue(historyResponse.contains("ASSIGNED"), "State history should contain ASSIGNED");


    }
}
