package cz.muni.fi.pa165.core.smartmeter;

import cz.muni.fi.pa165.core.device.Device;
import cz.muni.fi.pa165.core.device.DeviceRepository;
import cz.muni.fi.pa165.core.house.House;
import cz.muni.fi.pa165.core.house.HouseRepository;
import cz.muni.fi.pa165.core.metrics.Metrics;
import cz.muni.fi.pa165.core.metrics.MetricsRepository;
import cz.muni.fi.pa165.core.user.UserRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(SpringExtension.class)
@DataJpaTest
public class SmartMeterRepositoryTest {
	@Autowired
	private TestEntityManager entityManager;
	@Autowired
	private HouseRepository houseRepository;
	@Autowired
	private SmartMeterRepository smartMeterRepository;
	@Autowired
	private UserRepository userRepository;

	@Autowired
	private DeviceRepository deviceRepository;
	@Autowired
	private MetricsRepository metricsRepository;

	@Test
	void createTesting() {
		String m = entityManager.persistAndGetId(SmartMeter.builder().name("sm01").build()).toString();
		// Regular expression to match UUID format
		Pattern uuidPattern = Pattern.compile(
				"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
				Pattern.CASE_INSENSITIVE);
		// Check if the string matches the UUID format
		boolean isUUID = uuidPattern.matcher(m).matches();
		assertThat(isUUID).isTrue();
	}

	@Test
	public void shouldFindNoneIfRepositoryIsEmpty() {
		Iterable<SmartMeter> m = smartMeterRepository.findAll();
		assertThat(m).isEmpty();
	}

	@Test
	public void shouldStore() {
		SmartMeter smartMeter = helperRegister();

		assertThat(smartMeter).hasFieldOrPropertyWithValue("name", "OneT Tesla 1232");
	}

	@Test
	void shouldFindAll() {
		SmartMeter m = SmartMeter.builder().name("sm").build();
		entityManager.persist(m);

		SmartMeter m1 = SmartMeter.builder().name("sm01").build();
		entityManager.persist(m1);

		SmartMeter m2 = SmartMeter.builder().name("sm02").build();
		entityManager.persist(m2);

		assertThat(smartMeterRepository.findAll()).hasSize(3).contains(m, m1, m2);
	}

	@Test
	void shouldFindById() {
		SmartMeter m = SmartMeter.builder().name("sm").build();
		entityManager.persist(m);

		SmartMeter m1 = SmartMeter.builder().name("sm01").build();
		entityManager.persist(m1);

		SmartMeter m2 = SmartMeter.builder().name("sm01").build();
		entityManager.persist(m2);

		SmartMeter found = smartMeterRepository.findById(m.getId()).get();

		assertThat(found).isEqualTo(m);

		found = smartMeterRepository.findById(m.getId()).get();

		assertThat(found).isEqualTo(m);
	}

	@Test
	void shouldUpdateById() {
		SmartMeter m = SmartMeter.builder().name("sm").build();
		entityManager.persist(m);

		SmartMeter m1 = SmartMeter.builder().name("sm01").build();
		entityManager.persist(m1);

		SmartMeter update = smartMeterRepository.findById(m.getId()).get();
		update.setName("New name");
		smartMeterRepository.save(update);

		SmartMeter check = smartMeterRepository.findById(m.getId()).get();

		assertThat(check.getId()).isEqualTo(m.getId());
		assertThat(check.getName()).isEqualTo(m.getName());
	}

	@Test
	void shouldDeleteById() {
		SmartMeter m = SmartMeter.builder().name("sm").build();
		entityManager.persist(m);

		SmartMeter m1 = SmartMeter.builder().name("sm01").build();
		entityManager.persist(m1);

		smartMeterRepository.deleteById(m.getId());

		assertThat(smartMeterRepository.findAll()).hasSize(1).contains(m1);
		assertThat(smartMeterRepository.findAll()).hasSize(1).doesNotContain(m);
	}

	@Test
	void shouldDeleteAll() {
		entityManager.persist(helperRegister());

		smartMeterRepository.deleteAll();

		assertThat(smartMeterRepository.findAll()).isEmpty();
	}

	private SmartMeter helperRegister() {
		Iterable<Metrics> metrics;
		metrics = metricsRepository.saveAll(List.of(new Metrics(), new Metrics(), new Metrics()));
		List<Metrics> list = StreamSupport.stream(metrics.spliterator(), false)
				.collect(Collectors.toList());
		Device device = deviceRepository.save(Device.builder().name("dev01").build());
		House house = houseRepository.save(new House());
		return smartMeterRepository.save(new SmartMeter("OneT Tesla 1232", false, device, house, list));
	}
}


