package ch.unisg.roster.roster.application.service;

import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.roster.roster.application.port.in.AddRosterItemPort;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskCommand;
import ch.unisg.roster.roster.application.port.in.DeleteRosterItem;
import ch.unisg.roster.roster.application.port.in.NewTaskCommand;
import ch.unisg.roster.roster.application.port.out.NewTaskEventPort;
import ch.unisg.roster.roster.application.port.out.TaskAssignedEventPort;
import ch.unisg.roster.roster.application.port.out.TaskCompletedEventPort;
import ch.unisg.roster.roster.domain.Roster;
import ch.unisg.roster.roster.domain.RosterItem;
import ch.unisg.roster.roster.domain.Task;
import ch.unisg.roster.roster.domain.event.NewTaskEvent;
import ch.unisg.roster.roster.domain.event.TaskAssignedEvent;
import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.net.URI;
import java.util.Optional;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

public class AddNewAssignmentToRosterServiceTest {

    //private final NewTaskEventPort newTaskEventPort = Mockito.mock(NewTaskEventPort.class);
    private final TaskAssignedEventPort taskAssignedEventPort = Mockito.mock(TaskAssignedEventPort.class);
    private final AddRosterItemPort addRosterItemPort = Mockito.mock(AddRosterItemPort.class);
    //private final TaskCompletedEventPort taskCompletedEventPort = Mockito.mock(TaskCompletedEventPort.class)
    //private final DeleteRosterItem deleteRosterItem = Mockito.mock(DeleteRosterItem.class);

    //private final NewTaskService newTaskService = new NewTaskService(newTaskEventPort);
    private final ApplyForTaskService applyForTaskService = new ApplyForTaskService(taskAssignedEventPort,addRosterItemPort);
    //private final TaskCompletedService taskCompletedService = new TaskCompletedService(taskCompletedEventPort, deleteRosterItem);


    @Test
    void assigningSucceeds(){

        Task newTask = givenATaskWithIdAndType("test-id", "test-type", "test-input");
        RosterItem newRosterItem = givenARosterItemWithIdAndTypeAndExecutorUri("test-id", "test-type", "test-uri");
        // TODO Add task to queue

        ApplyForTaskCommand applyForTaskCommand = new ApplyForTaskCommand(newTask.getTaskType(), newRosterItem.getExecutorURI());

        Task assignedTask = applyForTaskService.applyForTask(applyForTaskCommand);

        assertThat(assignedTask).isNotNull();

        then(taskAssignedEventPort).should(times(1))
            .publishTaskAssignedEvent(any(TaskAssignedEvent.class));
        then(addRosterItemPort).should(times(1));
    }

    private RosterItem givenARosterItemWithIdAndTypeAndExecutorUri(String taskId, String taskType,
                                                        String executorURI){
        RosterItem rosterItem = Mockito.mock(RosterItem.class);
        given(rosterItem.getTaskID()).willReturn(taskId);
        given(rosterItem.getTaskType()).willReturn(taskType);
        given(rosterItem.getExecutorURI()).willReturn(new ExecutorURI(executorURI));
        return rosterItem;
    }

    private Task givenATaskWithIdAndType(String taskId, String taskType, String inputData) {
        Task task = Mockito.mock(Task.class);
        given(task.getTaskID()).willReturn(taskId);
        given(task.getTaskType()).willReturn(new ExecutorType(taskType));
        given(task.getInputData()).willReturn(inputData);
        return task;
    }
}

