package objective.taskboard.jira.properties;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

import objective.taskboard.TaskboardStartupMisconfiguredException;
import objective.taskboard.jira.FieldMetadataService;
import objective.taskboard.jira.MetadataService;

abstract class GuardTestDsl {

    protected JiraProperties jiraProperties = mock(JiraProperties.class);
    protected MetadataService metadataService = mock(MetadataService.class);
    protected FieldMetadataService fieldMetadataService = mock(FieldMetadataService.class);

    private JiraPropertiesMisconfiguredException actualException;

    public JiraPropertiesMocker<GuardTestDsl> jiraProperties() {
        return new JiraPropertiesMocker<GuardTestDsl>(jiraProperties, this);
    }

    public MetadataServiceMocker<GuardTestDsl> metadataService() {
        return new MetadataServiceMocker<GuardTestDsl>(metadataService, this);
    }

    public FieldMetadataServiceMocker<GuardTestDsl> fieldMetadataService() {
        return new FieldMetadataServiceMocker<GuardTestDsl>(fieldMetadataService, this);
    }

    public GuardTestDsl whenExecute(Runnable runnable) {
        try {
            runnable.run();
        } catch (JiraPropertiesMisconfiguredException e) {
            actualException = e;
        }
        return this;
    }

    public GuardTestAsserter then() {
        return new GuardTestAsserter();
    }

    protected class GuardTestAsserter {

        public GuardTestAsserter throwJiraPropertiesMisconfiguredException(String expectedDescription, String expectedAction) {
            assertThat(actualException).isNotNull();
            assertThat(actualException.getDescription()).isEqualTo(expectedDescription);
            assertThat(actualException.getAction()).isEqualTo(expectedAction);
            assertThat(actualException).isInstanceOf(TaskboardStartupMisconfiguredException.class);
            return this;
        }

        public GuardTestAsserter doesNotThrowException() {
            assertThat(actualException).isNull();
            return this;
        }
    }
}
