package com.drumonii.loltrollbuild.batch.scheduling;

import com.drumonii.loltrollbuild.batch.AllRetrievalsJobConfig;
import com.drumonii.loltrollbuild.batch.champions.ChampionsRetrievalJobConfig;
import com.drumonii.loltrollbuild.batch.items.ItemsRetrievalJobConfig;
import com.drumonii.loltrollbuild.batch.maps.MapsRetrievalJobConfig;
import com.drumonii.loltrollbuild.batch.summonerSpells.SummonerSpellsRetrievalJobConfig;
import com.drumonii.loltrollbuild.batch.versions.VersionsRetrievalJobConfig;
import com.drumonii.loltrollbuild.model.Version;
import com.drumonii.loltrollbuild.riot.service.VersionsService;
import com.drumonii.loltrollbuild.test.batch.BatchTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.SimpleTriggerContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

import static com.drumonii.loltrollbuild.batch.scheduling.RetrievalJobsScheduling.CRON_SCHEDULE;
import static com.drumonii.loltrollbuild.batch.scheduling.RetrievalJobsScheduling.LATEST_PATCH_KEY;
import static com.drumonii.loltrollbuild.config.Profiles.TESTING;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@RunWith(SpringRunner.class)
@BatchTest(includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = RetrievalJobsScheduling.class),
		jobs = { AllRetrievalsJobConfig.class, ChampionsRetrievalJobConfig.class, ItemsRetrievalJobConfig.class,
				MapsRetrievalJobConfig.class, SummonerSpellsRetrievalJobConfig.class, VersionsRetrievalJobConfig.class })
@ActiveProfiles({ TESTING })
public class RetrievalJobsSchedulingTest {

	@Autowired
	private RetrievalJobsScheduling retrievalJobsScheduling;

	@MockBean
	private VersionsService versionsService;

	@MockBean
	private JobLauncher jobLauncher;

	@Autowired
	@Qualifier("allRetrievalsJob")
	private Job allRetrievalsJob;

	@Test
	public void allRetrievalsCronExpression() {
		CronTrigger cronTrigger = new CronTrigger(CRON_SCHEDULE);

		LocalDateTime triggerDateTime = LocalDateTime.now().withHour(4).withMinute(0).withSecond(0).withNano(0);
		Date triggerDate = Date.from(triggerDateTime.atZone(ZoneId.systemDefault()).toInstant());

		SimpleTriggerContext triggerContext = new SimpleTriggerContext(triggerDate, triggerDate, triggerDate);

		Date nextExecutionDate = cronTrigger.nextExecutionTime(triggerContext);
		if (nextExecutionDate == null) {
			fail("Next Execution Time from the CronTrigger was null");
		}
		LocalDateTime nextExecutionDateTime = LocalDateTime.ofInstant(nextExecutionDate.toInstant(), ZoneId.systemDefault());

		assertThat(nextExecutionDateTime)
				.isEqualTo(LocalDateTime.now().plusDays(1).withHour(4).withMinute(0).withSecond(0).withNano(0));
	}

	@Test
	public void runsAllRetrievalsJob() throws Exception {
		given(versionsService.getLatestVersion()).willReturn(Version.patch("8.7.1"));

		retrievalJobsScheduling.runAllRetrievalsJob();

		verify(jobLauncher, times(1)).run(eq(allRetrievalsJob), any(JobParameters.class));
	}

	@Test
	public void skipsAllRetrievalsJobRunWithNoLatestPatch() throws Exception {
		given(versionsService.getLatestVersion()).willReturn(null);

		given(jobLauncher.run(eq(allRetrievalsJob), any(JobParameters.class)))
				.willThrow(new JobParametersInvalidException("The JobParameters do not contain required keys: " + LATEST_PATCH_KEY));

		retrievalJobsScheduling.runAllRetrievalsJob();
	}

	@Test
	public void runsAllRetrievalJobWithInstanceOfJobExecutionExceptionThrown() throws Exception {
		given(jobLauncher.run(eq(allRetrievalsJob), any(JobParameters.class)))
				.willThrow(new JobExecutionAlreadyRunningException("A job execution for this job is already running"));

		retrievalJobsScheduling.runAllRetrievalsJob();
	}

	@Test
	public void runsAllRetrievalJobWithExceptionThrown() throws Exception {
		given(versionsService.getLatestVersion()).willReturn(Version.patch("8.7.1"));

		given(jobLauncher.run(eq(allRetrievalsJob), any(JobParameters.class)))
				.willThrow(new NullPointerException());

		retrievalJobsScheduling.runAllRetrievalsJob();
	}

}

@@ -1981,70 +1981,9 @@
 ons.
-assertThat;%0Aimport static org.assertj.core.api.Assertions.fail
+*
 ;%0Aim
@@ -3875,32 +3875,53 @@
 h(%228.7.1%22));%0A%0A%09%09
+assertThatCode(() -%3E 
 retrievalJobsSch
@@ -3949,16 +3949,49 @@
 alsJob()
+)%0A%09%09%09%09.doesNotThrowAnyException()
 ;%0A%0A%09%09ver
@@ -4414,24 +4414,45 @@
 H_KEY));%0A%0A%09%09
+assertThatCode(() -%3E 
 retrievalJob
@@ -4476,32 +4476,65 @@
 lRetrievalsJob()
+)%0A%09%09%09%09.doesNotThrowAnyException()
 ;%0A%09%7D%0A%0A%09@Test%0A%09pu
@@ -4805,24 +4805,45 @@
 ning%22));%0A%0A%09%09
+assertThatCode(() -%3E 
 retrievalJob
@@ -4871,24 +4871,57 @@
 rievalsJob()
+)%0A%09%09%09%09.doesNotThrowAnyException()
 ;%0A%09%7D%0A%0A%09@Test
@@ -5195,16 +5195,37 @@
 ());%0A%0A%09%09
+assertThatCode(() -%3E 
 retrieva
@@ -5261,16 +5261,49 @@
 alsJob()
+)%0A%09%09%09%09.doesNotThrowAnyException()
 ;%0A%09%7D%0A%0A%7D%0A

Add test assertions that runAllRetrievalsJob does not throw an exception