package de.koudingspawn.vault.admissionreview;

import de.koudingspawn.vault.crd.DoneableVault;
import de.koudingspawn.vault.crd.Vault;
import de.koudingspawn.vault.crd.VaultList;
import de.koudingspawn.vault.vault.VaultSecret;
import de.koudingspawn.vault.vault.VaultService;
import de.koudingspawn.vault.vault.communication.SecretNotAccessibleException;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.internal.KubernetesDeserializer;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
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.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import java.util.HashMap;

import static org.mockito.ArgumentMatchers.any;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest(
        properties = {
                "kubernetes.vault.url=http://localhost:8206/v1/",
                "kubernetes.initial-delay=5000000",
                "kubernetes.vault.token=c73ab0cb-41e6-b89c-7af6-96b36f1ac87b"
        }
)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class AdmissionReviewTest {

    @MockBean
    VaultService vaultService;

    @MockBean
    MixedOperation<Vault, VaultList, DoneableVault, Resource<Vault, DoneableVault>> customResource;

    @Autowired
    private MockMvc mvc;

    @Before
    public void setup() {
        String kind = StringUtils.substringAfter("vault.koudingspawn.de", ".") + "/v1#Vault";
        KubernetesDeserializer.registerCustomKind(kind, Vault.class);
    }

    @Test
    public void shouldFailWithInvalidRequest() throws Exception {
        SecretNotAccessibleException secretException = new SecretNotAccessibleException("Secret is not accessible");
        Mockito.when(vaultService.generateSecret(any())).thenThrow(secretException);

        mvc.perform(post("/validation/vault-crd").content("{\n" +
                "  \"apiVersion\": \"admission.k8s.io/v1\",\n" +
                "  \"kind\": \"AdmissionReview\",\n" +
                "  \"request\": {\n" +
                "    \"uid\": \"705ab4f5-6393-11e8-b7cc-42010a800002\",\n" +
                "    \"object\": {\n" +
                "      \"apiVersion\": \"koudingspawn.de/v1\",\n" +
                "      \"kind\": \"Vault\",\n" +
                "      \"metadata\": {\n" +
                "        \"name\": \"test-vault\",\n" +
                "        \"namespace\": \"default\"\n" +
                "      " +
                "},\n" +
                "      \"spec\": {\n" +
                "        \"type\": \"KEYVALUE\",\n" +
                "        \"path\": \"secret/qweasd\"\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}").contentType("application/json"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.response.uid").value("705ab4f5-6393-11e8-b7cc-42010a800002"))
                .andExpect(jsonPath("$.response.allowed").value("false"))
                .andExpect(jsonPath("$.response.status.code").value("400"))
                .andExpect(jsonPath("$.response.status.message").value("Secret is not accessible"));
    }

    @Test
    public void shouldReturnValidValue() throws Exception {
        VaultSecret vaultSecret = new VaultSecret(new HashMap<>(), "qweasd");
        Mockito.when(vaultService.generateSecret(any())).thenReturn(vaultSecret);

        mvc.perform(post("/validation/vault-crd").content("{\n" +
                "  \"apiVersion\": \"admission.k8s.io/v1\",\n" +
                "  \"kind\": \"AdmissionReview\",\n" +
                "  \"request\": {\n" +
                "    \"uid\": \"705ab4f5-6393-11e8-b7cc-42010a800002\",\n" +
                "    \"object\": {\n" +
                "      \"apiVersion\": \"koudingspawn.de/v1\",\n" +
                "      \"kind\": \"Vault\",\n" +
                "      \"metadata\": {\n" +
                "        \"name\": \"test-vault\",\n" +
                "        \"namespace\": \"default\"\n" +
                "      " +
                "},\n" +
                "      \"spec\": {\n" +
                "        \"type\": \"KEYVALUE\",\n" +
                "        \"path\": \"secret/qweasd\"\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}").contentType("application/json"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.response.uid").value("705ab4f5-6393-11e8-b7cc-42010a800002"))
                .andExpect(jsonPath("$.response.allowed").value("true"));
    }

}