package com.atlassian.stash.internal.sal.scheduling;

import com.atlassian.sal.api.scheduling.PluginJob;
import com.atlassian.scheduler.JobRunnerRequest;
import com.atlassian.scheduler.SchedulerService;
import com.atlassian.scheduler.SchedulerServiceException;
import com.atlassian.scheduler.config.JobConfig;
import com.atlassian.scheduler.config.RunMode;
import com.atlassian.scheduler.config.Schedule;
import com.atlassian.scheduler.status.RunOutcome;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.atlassian.stash.internal.sal.scheduling.PluginSchedulerAdapter.toJobId;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class PluginSchedulerAdapterTest {

    @Mock
    private SchedulerService mockSchedulerService;

    @InjectMocks
    private PluginSchedulerAdapter underTest;

    @Test(expected = IllegalArgumentException.class)
    public void rejectsNonSerializableJobData() {
        Map jobDataMap = ImmutableMap.of("key", new PluginSchedulerAdapterTest());
        underTest.scheduleJob("foo", PluginJob.class, jobDataMap, new Date(), 1);
    }

    @Test
    public void acceptsNullJobData() {
        Map jobDataMap = new HashMap<String, Object>() { {
            put("foo", null);
        }};
        underTest.scheduleJob("foo", PluginJob.class, jobDataMap, new Date(), 1);
    }

    @Test
    public void acceptsSerializableJobData() {
        Map jobDataMap = ImmutableMap.of("key", "value");
        underTest.scheduleJob("foo", PluginJob.class, jobDataMap, new Date(), 1);
    }

    @Test
    public void scheduleJob() throws SchedulerServiceException {
        Map jobDataMap = ImmutableMap.of("key", "value");
        Date startTime = new Date();
        underTest.scheduleJob("foo", PluginJob.class, jobDataMap, startTime, 1);

        JobConfig jobConfig = JobConfig.forJobRunnerKey(PluginSchedulerAdapter.JOB_RUNNER_KEY)
                .withRunMode(RunMode.RUN_LOCALLY)
                .withSchedule(Schedule.forInterval(1, startTime));

        verify(mockSchedulerService).scheduleJob(toJobId("foo"), jobConfig);
    }

    @Test
    public void runJob() throws IllegalAccessException, InstantiationException {
        Map jobDataMap = ImmutableMap.of("key", "value");
        Date startTime = new Date();
        JobRunnerRequest jobRunnerRequest = mock(JobRunnerRequest.class);

        JobConfig jobConfig = JobConfig.forJobRunnerKey(PluginSchedulerAdapter.JOB_RUNNER_KEY)
                .withRunMode(RunMode.RUN_LOCALLY)
                .withParameters(jobDataMap)
                .withSchedule(Schedule.forInterval(1, startTime));

        when(jobRunnerRequest.getJobId()).thenReturn(toJobId("foo"));
        when(jobRunnerRequest.getJobConfig()).thenReturn(jobConfig);

        underTest.scheduleJob("foo", StubPluginJob.class, jobDataMap, startTime, 1);

        assertThat(underTest.runJob(jobRunnerRequest).getRunOutcome(), is(RunOutcome.SUCCESS));
    }

    private static class StubPluginJob implements PluginJob {

        public StubPluginJob() {
        }

        @Override
        public void execute(Map<String, Object> jobDataMap) {
        }
    }
}
