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

import cz.muni.fi.pa165.core.company.Company;
import cz.muni.fi.pa165.core.company.CompanyRepository;
import cz.muni.fi.pa165.core.house.HouseRepository;
import cz.muni.fi.pa165.core.smartmeter.SmartMeter;
import cz.muni.fi.pa165.core.smartmeter.SmartMeterRepository;
import cz.muni.fi.pa165.core.user.UserRepository;
import org.junit.Ignore;
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 DeviceRepositoryTest {
	@Autowired
	private TestEntityManager entityManager;
	@Autowired
	private HouseRepository houseRepository;
	@Autowired
	private SmartMeterRepository smartMeterRepository;
	@Autowired
	private DeviceRepository deviceRepository;
	@Autowired
	private CompanyRepository companyRepository;
	@Autowired
	private UserRepository userRepository;

	@Test
	void createDeviceTesting() {
		String device = entityManager.persistAndGetId(Device.builder().name("dev01").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(device).matches();
		assertThat(isUUID).isTrue();
	}

	@Test
	public void shouldFindNoDevicesIfRepositoryIsEmpty() {
		Iterable<Device> devices = deviceRepository.findAll();
		assertThat(devices).isEmpty();
	}

	@Test
	public void shouldStoreADevice() {
		Device device = helperRegisterDevice();

		assertThat(device).hasFieldOrPropertyWithValue("name", "Tesla Smart Meter A134");
	}

	@Test
	void shouldFindAllDevices() {
		Device device1 = Device.builder().name("dev01").build();
		entityManager.persist(device1);

		Device device2 = Device.builder().name("dev02").build();
		entityManager.persist(device2);

		assertThat(deviceRepository.findAll()).hasSize(2).contains(device1, device2);
	}

	@Test
	void shouldFindDeviceById() {
		Company company = Company.builder().name("Apple").build();
		Device device1 = Device.builder().name("dev01").company(company).build();
		entityManager.persist(device1);

		Device device2 = Device.builder().name("dev02").company(company).build();
		entityManager.persist(device2);

		Device foundDevice = deviceRepository.findById(device2.getId()).get();

		assertThat(foundDevice).isEqualTo(device2);

		foundDevice = deviceRepository.findById(device1.getId()).get();

		assertThat(foundDevice).isEqualTo(device1);
	}

	@Test
	void shouldUpdateDeviceById() {
		Device device1 = Device.builder().name("dev01").build();
		entityManager.persist(device1);

		Device device2 = Device.builder().name("dev02").build();
		entityManager.persist(device2);


		Device updatedDevice = deviceRepository.findById(device2.getId()).get();
		updatedDevice.setName("Smart Meter Gorenje V245");
		deviceRepository.save(updatedDevice);

		Device checkDevice = deviceRepository.findById(device2.getId()).get();

		assertThat(checkDevice.getId()).isEqualTo(device2.getId());
		assertThat(checkDevice.getName()).isEqualTo(device2.getName());
		assertThat(checkDevice.getCompany()).isEqualTo(device2.getCompany());
		assertThat(checkDevice.getCreatedAt()).isEqualTo(device2.getCreatedAt());
	}

	@Test
	void shouldDeleteById() {
		Device device1 = Device.builder().name("dev01").build();
		entityManager.persist(device1);

		Device device2 = Device.builder().name("dev02").build();
		entityManager.persist(device2);

		Device device = helperRegisterDevice();
		entityManager.persist(device);

		deviceRepository.deleteById(device.getId());

		assertThat(deviceRepository.findAll()).hasSize(2).doesNotContain(device);
	}

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

		houseRepository.deleteAll();

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

	private Device helperRegisterDevice() {
		Iterable<SmartMeter> smartMeterIterable;
		smartMeterIterable = smartMeterRepository.saveAll(List.of(SmartMeter.builder().name("sm01").build(),
				SmartMeter.builder().name("sm02").build(),
				SmartMeter.builder().name("sm03").build()));
		List<SmartMeter> list = StreamSupport.stream(smartMeterIterable.spliterator(), false)
				.collect(Collectors.toList());
		//need to save a user to the database first to asign him to the new device
		Company company = companyRepository.save(Company.builder().name("HP").build());
		return deviceRepository.save(new Device("Tesla Smart Meter A134", list, company));
	}
}