package cz.muni.fi.pa165.electricityTarifMicroservice.electricityprices;

import cz.muni.fi.pa165.electricityTarifMicroservice.electricityprices.dtos.ElectricityPriceGetFullDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;


class ElectricityPriceServiceTest {

	@InjectMocks
	private ElectricityPriceServiceImpl electricityPriceService;
	@Mock
	private ElectricityPriceMapperImpl electricityPriceMapper;
	@Mock
	private ElectricityPriceRepository electricityPriceRepository;

	@BeforeEach
	void setUp() {
		openMocks(this);
	}

	@Test
	void shouldGetAveragePriceLowTariff() {
		double avgLow = 200.0;
		when(electricityPriceRepository.averagePriceLowTariff()).thenReturn(avgLow);

		double result = electricityPriceService.averagePriceLowTariff();

		verify(electricityPriceRepository).averagePriceLowTariff();

		assertEquals(avgLow, result);
	}

	@Test
	void shouldGetAveragePriceHighTariff() {
		double avgHigh = 300.0;
		when(electricityPriceRepository.averagePriceLowTariff()).thenReturn(avgHigh);

		double result = electricityPriceService.averagePriceLowTariff();

		verify(electricityPriceRepository).averagePriceLowTariff();

		assertEquals(avgHigh, result);
	}

	@Test
	void shouldGetElectricityPriceObj() {
		ElectricityPrice electricityPrice = ElectricityPrice
				.builder()
				.companyId("1")
				.priceLowTariff(200.0)
				.priceHighTariff(300.0)
				.build();

		ElectricityPriceGetFullDto electricityPriceGetFullDto = new ElectricityPriceGetFullDto();
		electricityPriceGetFullDto.setCompanyId(electricityPrice.getCompanyId());
		electricityPriceGetFullDto.setPriceLowTariff(electricityPrice.getPriceLowTariff());
		electricityPriceGetFullDto.setPriceHighTariff(electricityPrice.getPriceHighTariff());
		electricityPriceGetFullDto.setId(1L);

		when(electricityPriceRepository.findByCompanyId(electricityPrice.getCompanyId())).thenReturn(electricityPrice);
		when(electricityPriceMapper.electricityPriceToElectricityPriceGetFullDto(electricityPrice)).thenReturn(electricityPriceGetFullDto);

		ElectricityPriceGetFullDto result = electricityPriceService.getElectricityPriceObj(electricityPrice.getCompanyId());

		verify(electricityPriceRepository).findByCompanyId(electricityPrice.getCompanyId());

		assertEquals(electricityPriceGetFullDto, result);
	}

	@Test
	void shouldGetElectricityPrice() {
		ElectricityPrice electricityPrice = ElectricityPrice
				.builder()
				.companyId("1")
				.priceLowTariff(200.0)
				.priceHighTariff(300.0)
				.build();

		when(electricityPriceRepository.findByCompanyId(electricityPrice.getCompanyId())).thenReturn(electricityPrice);

		double result = electricityPriceService.getElectricityPrice(electricityPrice.getCompanyId());

		verify(electricityPriceRepository).findByCompanyId(electricityPrice.getCompanyId());

		LocalTime localTime = LocalTime.now();
		LocalDate localDate = LocalDate.now();
		if (localDate.getDayOfWeek() != DayOfWeek.SATURDAY &&
				localDate.getDayOfWeek() != DayOfWeek.SUNDAY &&
				localTime.getHour() > 7 &&
				localTime.getHour() < 21)
			assertEquals(electricityPrice.getPriceHighTariff(), result);
		else
			assertEquals(electricityPrice.getPriceLowTariff(), result);

	}

	@Test
	void shouldGetAllElectricityPricePageable() {
		ElectricityPrice electricityPrice1 = ElectricityPrice
				.builder()
				.companyId("1")
				.priceLowTariff(200.0)
				.priceHighTariff(300.0)
				.build();

		ElectricityPriceGetFullDto electricityPriceGetFullDto1 = new ElectricityPriceGetFullDto();
		electricityPriceGetFullDto1.setCompanyId(electricityPrice1.getCompanyId());
		electricityPriceGetFullDto1.setPriceLowTariff(electricityPrice1.getPriceLowTariff());
		electricityPriceGetFullDto1.setPriceHighTariff(electricityPrice1.getPriceHighTariff());
		electricityPriceGetFullDto1.setId(1L);

		ElectricityPrice electricityPrice2 = ElectricityPrice
				.builder()
				.companyId("2")
				.priceLowTariff(250.0)
				.priceHighTariff(350.0)
				.build();

		ElectricityPriceGetFullDto electricityPriceGetFullDto2 = new ElectricityPriceGetFullDto();
		electricityPriceGetFullDto2.setCompanyId(electricityPrice2.getCompanyId());
		electricityPriceGetFullDto2.setPriceLowTariff(electricityPrice2.getPriceLowTariff());
		electricityPriceGetFullDto2.setPriceHighTariff(electricityPrice2.getPriceHighTariff());
		electricityPriceGetFullDto2.setId(2L);

		Page<ElectricityPrice> page = new PageImpl<>(List.of(electricityPrice1, electricityPrice2));
		Page<ElectricityPriceGetFullDto> page2 = new PageImpl<>(List.of(electricityPriceGetFullDto1, electricityPriceGetFullDto2));

		int pageNumber = 0;
		int pageSize = 10;

		when(electricityPriceRepository.findAll(PageRequest.of(pageNumber, pageSize))).thenReturn(page);
		when(electricityPriceMapper.mapToPageDto(page)).thenReturn(page2);


		Page<ElectricityPriceGetFullDto> result = electricityPriceService.getAllElectricityPricePagable(PageRequest.of(pageNumber, pageSize));

		verify(electricityPriceRepository).findAll(PageRequest.of(pageNumber, pageSize));

		assertThat(result).containsExactlyInAnyOrder(electricityPriceGetFullDto1, electricityPriceGetFullDto2);
	}

	@Test
	void shouldGetAllElectricityPrice() {
		ElectricityPrice electricityPrice1 = ElectricityPrice
				.builder()
				.companyId("1")
				.priceLowTariff(200.0)
				.priceHighTariff(300.0)
				.build();

		ElectricityPriceGetFullDto electricityPriceGetFullDto1 = new ElectricityPriceGetFullDto();
		electricityPriceGetFullDto1.setCompanyId(electricityPrice1.getCompanyId());
		electricityPriceGetFullDto1.setPriceLowTariff(electricityPrice1.getPriceLowTariff());
		electricityPriceGetFullDto1.setPriceHighTariff(electricityPrice1.getPriceHighTariff());
		electricityPriceGetFullDto1.setId(1L);

		ElectricityPrice electricityPrice2 = ElectricityPrice
				.builder()
				.companyId("2")
				.priceLowTariff(250.0)
				.priceHighTariff(350.0)
				.build();

		ElectricityPriceGetFullDto electricityPriceGetFullDto2 = new ElectricityPriceGetFullDto();
		electricityPriceGetFullDto2.setCompanyId(electricityPrice2.getCompanyId());
		electricityPriceGetFullDto2.setPriceLowTariff(electricityPrice2.getPriceLowTariff());
		electricityPriceGetFullDto2.setPriceHighTariff(electricityPrice2.getPriceHighTariff());
		electricityPriceGetFullDto2.setId(2L);

		var list = List.of(
				electricityPrice1,
				electricityPrice2
		);

		var listDto = List.of(
				electricityPriceGetFullDto1,
				electricityPriceGetFullDto2
		);

		when(electricityPriceRepository.findAll()).thenReturn(list);
		when(electricityPriceMapper.electricityPriceListToElectricityPriceGetFullDtoList(list)).thenReturn(listDto);


		List<ElectricityPriceGetFullDto> result = electricityPriceService.getAllElectricityPrice();

		verify(electricityPriceRepository).findAll();

		assertEquals(listDto, result);
	}
}