package com.ruoyi.web.controller.front;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockDefinition;
import com.ruoyi.generator.service.front.BusinessBlockRegistryService;
import com.ruoyi.generator.domain.front.dto.ProjectRunPreviewStatus;
import com.ruoyi.generator.service.front.IFrontProjectService;
import com.ruoyi.generator.service.front.IFrontProjectRunPreviewService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

import java.lang.reflect.Field;
import java.util.Collections;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class FrontProjectControllerRunPreviewTest
{
    private FrontProjectController controller;

    @Mock
    private IFrontProjectRunPreviewService frontProjectRunPreviewService;
    @Mock
    private BusinessBlockRegistryService businessBlockRegistryService;
    @Mock
    private IFrontProjectService frontProjectService;

    @Before
    public void setUp() throws Exception
    {
        MockitoAnnotations.initMocks(this);
        controller = new FrontProjectController();
        setField("frontProjectRunPreviewService", frontProjectRunPreviewService);
        setField("businessBlockRegistryService", businessBlockRegistryService);
        setField("frontProjectService", frontProjectService);
        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(loginUser(), null));
    }

    @After
    public void tearDown()
    {
        SecurityContextHolder.clearContext();
    }

    @Test
    public void startRunPreviewDelegatesToCurrentFrontUser()
    {
        ProjectRunPreviewStatus status = status(ProjectRunPreviewStatus.RUNNING);
        when(frontProjectRunPreviewService.start(7L, 20L)).thenReturn(status);

        AjaxResult result = controller.startRunPreview(20L);

        assertEquals(status, result.get(AjaxResult.DATA_TAG));
        verify(frontProjectRunPreviewService).start(7L, 20L);
    }

    @Test
    public void getRunPreviewStatusDelegatesToCurrentFrontUser()
    {
        ProjectRunPreviewStatus status = status(ProjectRunPreviewStatus.NOT_STARTED);
        when(frontProjectRunPreviewService.status(7L, 20L)).thenReturn(status);

        AjaxResult result = controller.runPreviewStatus(20L);

        assertEquals(status, result.get(AjaxResult.DATA_TAG));
        verify(frontProjectRunPreviewService).status(7L, 20L);
    }

    @Test
    public void stopRunPreviewDelegatesToCurrentFrontUser()
    {
        ProjectRunPreviewStatus status = status(ProjectRunPreviewStatus.STOPPED);
        when(frontProjectRunPreviewService.stop(7L, 20L)).thenReturn(status);

        AjaxResult result = controller.stopRunPreview(20L);

        assertEquals(status, result.get(AjaxResult.DATA_TAG));
        verify(frontProjectRunPreviewService).stop(7L, 20L);
    }

    @Test
    public void businessBlocksChecksOwnershipAndFiltersScope()
    {
        BusinessBlockDefinition definition = new BusinessBlockDefinition();
        definition.setCode("admin_line_chart");
        when(businessBlockRegistryService.listDefinitions("admin"))
                .thenReturn(Collections.singletonList(definition));

        AjaxResult result = controller.businessBlocks(20L, "admin");

        assertEquals(Collections.singletonList(definition), result.get(AjaxResult.DATA_TAG));
        verify(frontProjectService).getProject(7L, 20L);
        verify(businessBlockRegistryService).listDefinitions("admin");
    }

    private ProjectRunPreviewStatus status(String value)
    {
        ProjectRunPreviewStatus status = new ProjectRunPreviewStatus();
        status.setProjectId(20L);
        status.setStatus(value);
        return status;
    }

    private LoginUser loginUser()
    {
        SysUser user = new SysUser();
        user.setUserName("front");
        user.setPassword("password");
        LoginUser loginUser = new LoginUser(7L, 1L, user, Collections.<String>emptySet());
        loginUser.setLoginType("front");
        return loginUser;
    }

    private void setField(String name, Object value) throws Exception
    {
        Field field = FrontProjectController.class.getDeclaredField(name);
        field.setAccessible(true);
        field.set(controller, value);
    }
}
