package edu.prlab.tyler.iotgateway.cloud;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.prlab.tyler.iotgateway.cloud.pojo.auth.SensitiveUser;
import edu.prlab.tyler.iotgateway.cloud.pojo.device.Device;
import edu.prlab.tyler.iotgateway.cloud.pojo.device.Icon;
import edu.prlab.tyler.iotgateway.cloud.pojo.device.Model;
import edu.prlab.tyler.iotgateway.cloud.pojo.privacy.PrivacyChoice;
import edu.prlab.tyler.iotgateway.cloud.pojo.privacy.PrivacyContent;
import edu.prlab.tyler.iotgateway.cloud.pojo.privacy.PrivacyPolicy;
import edu.prlab.tyler.iotgateway.cloud.pojo.privacy.PrivacyPolicyReport;
import edu.prlab.tyler.iotgateway.cloud.pojo.privacy.p3p.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.util.Arrays;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = CloudApplication.class)
public class CloudHttpApiTest {
    @Autowired
    WebApplicationContext context;

    private MockMvc mvc;
    private ObjectMapper mapper;

    @Before
    public void setup() {
        this.mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .build();
        this.mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
    }

    @Test
    public void addAndGetDevice() throws Exception {

        Device device = Device.builder()
                .udn("udn")
                .name("name")
                .type(Device.Type.Sensor)
                .UPC("upc")
                .model(Model.builder()
                        .name("name")
                        .url("url")
                        .description("description")
                        .build())
                .location("location")
                .icons(Arrays.asList(Icon.builder()
                        .build()))
                .status(Device.Status.Disconnected)
                .build();

        MvcResult result = mvc.perform(MockMvcRequestBuilders
                .post("/device")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .content(mapper.writeValueAsString(device)))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
        device = mapper.readValue(result.getResponse().getContentAsString(), Device.class);
        System.out.println("The return device = " + device.toString());
        Assert.assertNotNull(device);



        result = mvc.perform(MockMvcRequestBuilders
                .get("/device")
                .accept(MediaType.APPLICATION_JSON_UTF8))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
        Iterable<Device> devices = mapper.readValue(result.getResponse().getContentAsString(),
                new TypeReference<Iterable<Device>>() {
                });
        Assert.assertNotNull(devices);

        result = mvc.perform(MockMvcRequestBuilders
                .get("/device/" + device.getUdn())
                .accept(MediaType.APPLICATION_JSON_UTF8))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
        device = mapper.readValue(result.getResponse().getContentAsString(), Device.class);
        Assert.assertNotNull(device);

        PrivacyPolicy oxygenPrivacyPolicy = PrivacyPolicy.builder()
                .id("abe5ca7b-780e-4857-87e6-014870fe0a32")
                .description("本APP會蒐集使用者周遭溫度作為第三方資料之地區環境分析資料。")
                .collector(Collector.builder()
                        .name("AirRadio")
                        .email("airradio@gmail.com.tw")
                        .phone("0987654177")
                        .build())
                .remedies(Arrays.asList(Remedy.builder()
                        .type(Remedy.Type.LAW)
                        .build()))
                .statements(Arrays.asList(Statement.builder()
                        .consequence("a1252c49-4188-4e6d-a32e-66604c664fb9")
                        .purposes(Arrays.asList(Purpose.builder()
                                .type(Purpose.Type.PSEUDO_ANALYSIS)
                                .description("本APP會蒐集使用者周遭溫度作為第三方資料之地區環境分析資料。")
                                .build()))
                        .data(Arrays.asList(Datum.builder()
                                .type(Datum.Type.OTHER_CATEGORY)
                                .description("室溫資料")
                                .build()))
                        .recipients(Arrays.asList(Recipient.builder()
                                .entity("AirRadio")
                                .type(Recipient.Type.OURS)
                                .build()))
                        .retention(Retention.STATED_PURPOSE)
                        .build(), Statement.builder()
                        .consequence("a1252c49-4188-4e6d-a32e-66604c664fb9")
                        .purposes(Arrays.asList(Purpose.builder()
                                .type(Purpose.Type.PSEUDO_ANALYSIS)
                                .description("本APP會蒐集使用者周遭溫度作為第三方資料之地區環境分析資料。")
                                .build()))
                        .data(Arrays.asList(Datum.builder()
                                .type(Datum.Type.OTHER_CATEGORY)
                                .description("室溫資料")
                                .build()))
                        .recipients(Arrays.asList(Recipient.builder()
                                .entity("AirRadio")
                                .type(Recipient.Type.OURS)
                                .build()))
                        .retention(Retention.STATED_PURPOSE)
                        .build()
                ))
                .build();

        PrivacyPolicyReport privacyPolicyReport = PrivacyPolicyReport.builder()
                .id("0cfb6be3-6f0f-4e63-85b8-e9c936707c0b")
                .version("1.0")
                .description("本APP會蒐集使用者周遭溫度、濕度及空氣品質作為第三方資料之地區環境分析資料。")
                .device(device)
                .policies(Arrays.asList(oxygenPrivacyPolicy))
                .build();

        result = mvc.perform(MockMvcRequestBuilders
                .post("/privacy")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .content(mapper.writeValueAsString(privacyPolicyReport)))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
        PrivacyPolicyReport returnPolicy = mapper.readValue(result.getResponse().getContentAsString(),
                PrivacyPolicyReport.class);
        Assert.assertNotNull(returnPolicy);

        result = mvc.perform(MockMvcRequestBuilders
                .get("/privacy/" + device.getUdn())
                .accept(MediaType.APPLICATION_JSON_UTF8))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
        PrivacyPolicyReport report = mapper.readValue(result.getResponse().getContentAsString(), PrivacyPolicyReport.class);
        Assert.assertNotNull(report);

        PrivacyChoice privacyChoice = PrivacyChoice.builder()
                .privacyContent(PrivacyContent.builder()
                        .user(SensitiveUser.builder()
                                .username("test")
                                .password("test")
                                .build())
                        .device(device)
                        .policy(report.getPolicies().get(0))
                        .build())
                .isAccepted(true)
                .build();

        result = mvc.perform(MockMvcRequestBuilders
                .post("/choice")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .accept(MediaType.APPLICATION_JSON_UTF8)
                .content(mapper.writeValueAsString(privacyChoice)))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();

        Assert.assertNotNull(result);

        result = mvc.perform(MockMvcRequestBuilders
                .get("/choice")
                .accept(MediaType.APPLICATION_JSON_UTF8))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
        Iterable<PrivacyChoice> privacyChoices = mapper.readValue(result.getResponse().getContentAsString(),
                new TypeReference<Iterable<PrivacyChoice>>(){});

        Assert.assertNotNull(privacyChoices);
    }
}
