package com.zsc.edu.gateway.rest.iot;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zsc.edu.gateway.MockMvcConfigBase;
import com.zsc.edu.gateway.domain.iot.PropertyBuilder;
import com.zsc.edu.gateway.modules.iot.tsl.controller.PropertyController;
import com.zsc.edu.gateway.modules.iot.tsl.dto.PropertyDto;
import com.zsc.edu.gateway.modules.iot.tsl.entity.DataType;
import com.zsc.edu.gateway.modules.iot.tsl.entity.Property;
import com.zsc.edu.gateway.modules.iot.tsl.service.PropertyService;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Spy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;

import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(PropertyController.class)
public class PropertyControllerTest extends MockMvcConfigBase {
    @Spy
    private static Property property1;
    private static Property property2;
    @MockBean
    private PropertyService service;

    @Autowired
    private ObjectMapper objectMapper;

    @BeforeAll
    static void beforeAll() {
        property1 = PropertyBuilder.builder().setName("PROPERTY_NAME_1").setProductId(121L)
                .setIoType(Property.IoType.READ_WRITE).setDataType(DataType.DATE).build();
        property1.setId(1L);
        property2 = PropertyBuilder.builder().setName("PROPERTY_NAME_2").setProductId(121L)
                .setIoType(Property.IoType.READ_WRITE).setDataType(DataType.DATE).build();
        property2.setId(2L);
    }

    @Test
    void create() throws Exception {
        PropertyDto dto = new PropertyDto();
        dto.setProductId(121L);
        dto.setName(property1.getName());
        dto.setIdentifier("Identifier 1");
        dto.setDataType(DataType.DATE);
        dto.setIoType(Property.IoType.READ_WRITE);
        when(service.create(any(PropertyDto.class))).thenReturn(property1);
        mockMvc.perform(post("/api/rest/tsl/property")
                        .with(csrf().asHeader())
                        .with(user(userDetails))
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(dto))
                )
                .andExpect(status().isOk())
                .andDo(print());
        verify(service).create(any(PropertyDto.class));
    }

    @Test
    void list() throws Exception {
        List<Property> properties = Lists.newArrayList(property1, property2);
        when(service.page(any(Page.class), any(LambdaQueryWrapper.class))).thenReturn(new Page<Property>().setRecords(properties).setTotal((long) properties.size()));
        mockMvc.perform(get("/api/rest/tsl/property").with(user(userDetails)))
                .andExpect(status().isOk())
                .andDo(print());
        verify(service).page(any(Page.class), any(LambdaQueryWrapper.class));
    }

    @Test
    void update() throws Exception {
        PropertyDto dto = new PropertyDto();
        dto.setProductId(121L);
        dto.setName("PROPERTY_UPDATE");
        dto.setIdentifier("Identifier 1");
        dto.setDataType(DataType.DATE);
        dto.setIoType(Property.IoType.READ_WRITE);
        when(service.update(any(PropertyDto.class), anyLong())).thenReturn(property1);
        mockMvc.perform(patch("/api/rest/tsl/property/{id}", property1.getId())
                        .with(csrf().asHeader())
                        .with(user(userDetails))
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(dto))
                )
                .andExpect(status().isOk())
                .andDo(print());
        verify(service).update(any(PropertyDto.class), anyLong());
    }
}
