package org.brapi.test.BrAPITestServer.service.core;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerDbIdNotFoundException;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
import org.brapi.test.BrAPITestServer.model.entity.core.CropEntity;
import org.brapi.test.BrAPITestServer.repository.core.CropRepository;
import org.brapi.test.BrAPITestServer.service.PagingUtility;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import io.swagger.model.Metadata;
import io.swagger.model.core.CommonCrop;

@Service
public class CropService {

	private CropRepository cropRepository;

	public CropService(CropRepository cropRepository) {
		this.cropRepository = cropRepository;
	}

	public List<String> getCrops(Metadata metaData) {

		Page<CropEntity> cropsPage = cropRepository.findAll(PagingUtility.getPageRequest(metaData));
		List<String> crops = cropsPage.stream().map(c -> {
			return c.getCropName();
		}).collect(Collectors.toList());

		PagingUtility.calculateMetaData(metaData, cropsPage);
		return crops;
	}

	public CropEntity findCropEntity(String commonCropName) throws BrAPIServerException {
		CropEntity entity = null;
		if (commonCropName != null) {
			List<CropEntity> cropsPage = cropRepository.findByCropName(commonCropName, PageRequest.of(0, 1))
					.getContent();

			if (cropsPage.size() >= 1) {
				entity = cropsPage.get(0);
			}
		}
		return entity;
	}

	public CropEntity getCropEntity(String commonCropName) throws BrAPIServerException {
		CropEntity entity = null;
		if (commonCropName != null) {
			List<CropEntity> cropsPage = cropRepository.findByCropName(commonCropName, PageRequest.of(0, 1))
					.getContent();

			if (cropsPage.size() == 1) {
				entity = cropsPage.get(0);
			} else {
				throw new BrAPIServerDbIdNotFoundException("crop name", commonCropName, "crop name", HttpStatus.NOT_FOUND);
			}
		}
		return entity;
	}

	public CropEntity saveCropEntity(String commonCropName)  throws BrAPIServerException {
		CropEntity entity = null;
		if (commonCropName != null) {
			entity = new CropEntity();
			entity.setCropName(commonCropName);
			entity = cropRepository.saveAndFlush(entity);
		}
		return entity;
	}

	public CommonCrop createCrop(String commonCropName) throws BrAPIServerException {
		String name = validateCropName(commonCropName);
		if (findCropEntity(name) != null) {
			throw new BrAPIServerException(HttpStatus.CONFLICT, "Crop already exists: " + name);
		}
		return convertToCommonCrop(saveCropEntity(name));
	}

	public CommonCrop updateCrop(String cropDbId, String commonCropName) throws BrAPIServerException {
		String name = validateCropName(commonCropName);
		CropEntity entity = resolveCropEntity(cropDbId);
		if (!name.equals(entity.getCropName()) && findCropEntity(name) != null) {
			throw new BrAPIServerException(HttpStatus.CONFLICT, "Crop already exists: " + name);
		}
		entity.setCropName(name);
		return convertToCommonCrop(cropRepository.saveAndFlush(entity));
	}

	public CommonCrop deleteCrop(String cropDbId) throws BrAPIServerException {
		CropEntity entity = resolveCropEntity(cropDbId);
		CommonCrop deleted = convertToCommonCrop(entity);
		try {
			cropRepository.delete(entity);
			cropRepository.flush();
		} catch (DataIntegrityViolationException e) {
			throw new BrAPIServerException(HttpStatus.CONFLICT, "Crop is in use and cannot be deleted");
		}
		return deleted;
	}

	private CropEntity resolveCropEntity(String cropDbId) throws BrAPIServerException {
		Optional<CropEntity> byId = cropRepository.findById(cropDbId);
		if (byId.isPresent()) {
			return byId.get();
		}
		return getCropEntity(cropDbId);
	}

	private String validateCropName(String commonCropName) throws BrAPIServerException {
		if (commonCropName == null || commonCropName.isBlank()) {
			throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "commonCropName is required");
		}
		return commonCropName.trim();
	}

	public CommonCrop convertToCommonCrop(CropEntity entity) {
		CommonCrop crop = new CommonCrop();
		if (entity != null) {
			crop.setCropDbId(entity.getCropName());
			crop.setCommonCropName(entity.getCropName());
		}
		return crop;
	}

}
