package ch.unisg.executorpool;

import static org.mockito.Mockito.times;

import java.net.URI;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.BDDMockito.*;
import static org.assertj.core.api.Assertions.*;

import ch.unisg.executorpool.application.port.in.AddNewExecutorToExecutorPoolCommand;
import ch.unisg.executorpool.application.port.out.AddExecutorPort;
import ch.unisg.executorpool.application.port.out.ExecutorAddedEventPort;
import ch.unisg.executorpool.application.service.AddNewExecutorToExecutorPoolService;
import ch.unisg.executorpool.domain.ExecutorAddedEvent;
import ch.unisg.executorpool.domain.ExecutorClass;
import ch.unisg.executorpool.domain.ExecutorPool;
import ch.unisg.executorpool.domain.ExecutorClass.ExecutorUri;

public class AddNewExecutorToExecutorPoolServiceTest {

    private final AddExecutorPort addExecutorPort = Mockito.mock(AddExecutorPort.class);
    private final ExecutorAddedEventPort newExecutorAddedEventPort = Mockito.mock(ExecutorAddedEventPort.class);
    private final AddNewExecutorToExecutorPoolService addNewExecutorToExecutorPoolService = new AddNewExecutorToExecutorPoolService(
        newExecutorAddedEventPort, addExecutorPort); 

    @Test
    void addingSucceeds() {

        ExecutorClass newExecutor = givenAnExecutorWithTypeAndUri(new ExecutorClass.ExecutorTaskType("test-type"), 
        new ExecutorClass.ExecutorUri(URI.create("example.org")));

        ExecutorPool executorPool = givenAnEmptyExecutorPool(ExecutorPool.getExecutorPool());

        AddNewExecutorToExecutorPoolCommand addNewExecutorToExecutorPoolCommand = new AddNewExecutorToExecutorPoolCommand(
            newExecutor.getExecutorUri(), newExecutor.getExecutorTaskType());

        ExecutorClass addedExecutor = addNewExecutorToExecutorPoolService.addNewExecutorToExecutorPool(addNewExecutorToExecutorPoolCommand);

        assertThat(addedExecutor).isNotNull();
        assertThat(executorPool.getListOfExecutors().getValue()).hasSize(1);

        then(newExecutorAddedEventPort).should(times(1)).publishExecutorAddedEvent(any(ExecutorAddedEvent.class));

    }


    private ExecutorPool givenAnEmptyExecutorPool(ExecutorPool executorPool) {
        executorPool.getListOfExecutors().getValue().clear();
        return executorPool;
    } 

    private ExecutorClass givenAnExecutorWithTypeAndUri(ExecutorClass.ExecutorTaskType executorTaskType, 
    ExecutorUri executorUri) {

        ExecutorClass executor = Mockito.mock(ExecutorClass.class);
        given(executor.getExecutorTaskType()).willReturn(executorTaskType);
        given(executor.getExecutorUri()).willReturn(executorUri);
        return executor;
    }


    
}
