package com.vaessl.app.search;

import static com.vaessl.app.Mockdata.MOCK_PASS;
import static com.vaessl.app.Mockdata.MOCK_USER;
import static com.vaessl.app.shared.Endpoint.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import jakarta.servlet.http.Cookie;

@SpringBootTest
@AutoConfigureMockMvc
@WireMockTest
class SearchControllerTest {

    @Autowired
    MockMvc mockMvc;

    private static final String QUERY_ALL_ITEMS = HOMEBOX_QUERY_ALL_ITEMS.getValue();

    private static final String LOGIN_PATH = LOGIN.getValue();

    private static final String SEARCH_REQUEST = SEARCH.getValue();

    private static final String VALID_HOMEBOX_LOGIN_RESPONSE = """
            {
                "token": "fake-bearer-token",
                "attachmentToken": "fake-attach-token",
                "expiresAt": "2099-01-01T00:00:00Z"
            }
            """;

    private static final String VALID_HOMEBOX_ALL_ITEMS_QUERY_RESPONSE = """
            {
                "page": -1,
                "pageSize": -1,
                "total": 1,
                "items": [
                    {
                        "id": "c643e7f9-93d0-4b5f-ae4d-e1c2d90389e0",
                        "assetId": "000-001",
                        "name": "MacBook Pro A1398",
                        "description": "Running Linux (Fedora)",
                        "quantity": 1,
                        "insured": false,
                        "archived": false,
                        "createdAt": "2026-05-13T19:52:20.016176Z",
                        "updatedAt": "2026-05-14T12:39:11.836403Z",
                        "purchasePrice": 0,
                        "parent": {
                            "id": "b6f60ab8-3a2a-4a8d-a4bf-897d0555f636",
                            "name": "Server Schrank Ikea weiß",
                            "description": "Weißer Ikea Schrank, wo sich der Server befindet.",
                            "createdAt": "2026-05-13T19:55:55.817576Z",
                            "updatedAt": "2026-05-14T12:37:24.396651Z"
                        },
                        "tags": [],
                        "imageId": "cb3e44d5-ccd4-421e-9f5a-f52cd5f40ca6",
                        "thumbnailId": "2bfd53fa-1bf1-483c-8d76-7720464532fa",
                        "soldTime": "0001-01-01T00:00:00Z"
                    }
                ]
            }
            """;

    @Test
    void shouldReturnListOfQueriedHomeboxItems(WireMockRuntimeInfo wm) throws Exception {

        WireMock.stubFor(WireMock.post(HOMEBOX_LOGIN.getValue())
                .willReturn(WireMock.okJson(VALID_HOMEBOX_LOGIN_RESPONSE)));

        WireMock.stubFor(WireMock.get(WireMock.urlPathEqualTo(QUERY_ALL_ITEMS))
                .willReturn(WireMock.okJson(VALID_HOMEBOX_ALL_ITEMS_QUERY_RESPONSE)));

        MvcResult loginResult =
                mockMvc.perform(post(LOGIN_PATH).contentType(MediaType.APPLICATION_JSON)
                        .content(connectionRequestBody(wm))).andExpect(status().isOk()).andReturn();

        Cookie sessionCookie = loginResult.getResponse().getCookie("SESSION");

        mockMvc.perform(post(SEARCH_REQUEST).cookie(sessionCookie)
                .contentType(MediaType.APPLICATION_JSON).content(searchRequestBody(wm, "HOMEBOX")))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.content[0].title").value("MacBook Pro A1398"))
                .andExpect(jsonPath("$.totalElements").value(1))
                .andExpect(jsonPath("$.content[0].extraData.locationName").value("Server Schrank Ikea weiß"));
    }

    @Test
    void shouldReturnUnauthorizedWhenNoSession() throws Exception {
        mockMvc.perform(post(SEARCH_REQUEST).contentType(MediaType.APPLICATION_JSON).content("""
                {
                    "appUrl": "http://irrelevant",
                    "query": "Item",
                    "serviceType": "HOMEBOX",
                    "username": "irrelevant",
                    "aiSearch": false
                }
                """)).andExpect(status().isUnauthorized());
    }

    @Test
    void shouldReturnBadRequestWhenServiceTypeIsInvalid() throws Exception {
        mockMvc.perform(post(SEARCH_REQUEST).contentType(MediaType.APPLICATION_JSON)
                .content(searchRequestBody("INVALID_SERVICETYPE")))
                .andExpect(status().isBadRequest());
    }

    private String searchRequestBody(WireMockRuntimeInfo wm, String serviceType) {
        return searchRequestBody(wm.getHttpBaseUrl(), serviceType, false);
    }

    private String searchRequestBody(String serviceType) {
        return searchRequestBody("http://irrelevant", serviceType, false);
    }

    private String searchRequestBody(String appUrl, String serviceType, boolean aiSearch) {
        return """
                {
                    "appUrl": "%s",
                    "query": "Item",
                    "serviceType": "%s",
                    "username": "%s",
                    "aiSearch": "%b"
                }
                """.formatted(appUrl, serviceType, MOCK_USER, aiSearch);
    }

    private String connectionRequestBody(WireMockRuntimeInfo wm) {
        return """
                {
                    "appUrl": "%s",
                    "serviceType": "HOMEBOX",
                    "username": "%s",
                    "password": "%s"
                }
                """.formatted(wm.getHttpBaseUrl(), MOCK_USER, MOCK_PASS);
    }
}
