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

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import jakarta.validation.Valid;

import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerDbIdNotFoundException;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
import org.brapi.test.BrAPITestServer.model.entity.germ.BreedingMethodEntity;
import org.brapi.test.BrAPITestServer.repository.germ.BreedingMethodRepository;
import org.brapi.test.BrAPITestServer.repository.germ.GermplasmRepository;
import org.brapi.test.BrAPITestServer.service.PagingUtility;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import io.swagger.model.Metadata;
import io.swagger.model.germ.BreedingMethod;

@Service
public class BreedingMethodService {
	
	private final BreedingMethodRepository breedingMethodRepository;
	private final GermplasmRepository germplasmRepository;
	
	public BreedingMethodService(BreedingMethodRepository breedingMethodRepository,
			GermplasmRepository germplasmRepository) {
		this.breedingMethodRepository = breedingMethodRepository;
		this.germplasmRepository = germplasmRepository;
	}

	public List<BreedingMethod> findBreedingMethods(Metadata metadata) {
		Pageable pageReq = PagingUtility.getPageRequest(metadata);
		Page<BreedingMethodEntity> page = breedingMethodRepository.findAll(pageReq);
		List<BreedingMethod> breedingMethods = page.map(this::convertFromEntity).getContent();
		PagingUtility.calculateMetaData(metadata, page);
		return breedingMethods;
	}

	public BreedingMethod getBreedingMethod(String breedingMethodDbId) throws BrAPIServerException {
		return convertFromEntity(getBreedingMethodEntity(breedingMethodDbId, HttpStatus.NOT_FOUND));
	}

	public BreedingMethodEntity getBreedingMethodEntity(String breedingMethodDbId) throws BrAPIServerException {
		return getBreedingMethodEntity(breedingMethodDbId, HttpStatus.BAD_REQUEST);
	}

	public BreedingMethodEntity getBreedingMethodEntity(String breedingMethodDbId, HttpStatus errorStatus) throws BrAPIServerException {
		BreedingMethodEntity breedingMethodEntity = null;
		Optional<BreedingMethodEntity> entityOpt = breedingMethodRepository.findById(breedingMethodDbId);
		if (entityOpt.isPresent()) {
			breedingMethodEntity = entityOpt.get();
		} else {
			throw new BrAPIServerDbIdNotFoundException("breedingMethod", breedingMethodDbId, errorStatus);
		}
		return breedingMethodEntity;
	}

	public List<BreedingMethod> saveBreedingMethods(@Valid List<BreedingMethod> body) throws BrAPIServerException {
		List<BreedingMethod> savedMethods = new ArrayList<>();

		for (BreedingMethod method : body) {
			validateBreedingMethodName(method.getBreedingMethodName());
			BreedingMethodEntity entity = new BreedingMethodEntity();
			updateEntity(entity, method);
			BreedingMethodEntity savedEntity = breedingMethodRepository.save(entity);
			savedMethods.add(convertFromEntity(savedEntity));
		}

		return savedMethods;
	}

	public BreedingMethod updateBreedingMethod(String breedingMethodDbId, BreedingMethod body) throws BrAPIServerException {
		BreedingMethodEntity entity = getBreedingMethodEntity(breedingMethodDbId, HttpStatus.NOT_FOUND);
		updateEntity(entity, body);
		BreedingMethodEntity savedEntity = breedingMethodRepository.save(entity);
		return convertFromEntity(savedEntity);
	}

	public BreedingMethod deleteBreedingMethod(String breedingMethodDbId) throws BrAPIServerException {
		BreedingMethodEntity entity = getBreedingMethodEntity(breedingMethodDbId, HttpStatus.NOT_FOUND);
		long usageCount = germplasmRepository.countByBreedingMethod_Id(breedingMethodDbId);
		if (usageCount > 0) {
			throw new BrAPIServerException(HttpStatus.CONFLICT,
					"Breeding method is in use by germplasm and cannot be deleted");
		}
		BreedingMethod deleted = convertFromEntity(entity);
		breedingMethodRepository.delete(entity);
		breedingMethodRepository.flush();
		return deleted;
	}

	public long countGermplasmUsage(String breedingMethodDbId) {
		return germplasmRepository.countByBreedingMethod_Id(breedingMethodDbId);
	}

	private void validateBreedingMethodName(String breedingMethodName) throws BrAPIServerException {
		if (breedingMethodName == null || breedingMethodName.trim().isEmpty()) {
			throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "breedingMethodName is required");
		}
	}

	private BreedingMethod convertFromEntity(BreedingMethodEntity entity) {
		BreedingMethod method = new BreedingMethod();
		method.setAbbreviation(entity.getAbbreviation());
		method.setBreedingMethodDbId(entity.getId());
		method.setBreedingMethodName(entity.getName());
		method.setDescription(entity.getDescription());
		return method;
	}

	private void updateEntity(BreedingMethodEntity entity, BreedingMethod request) throws BrAPIServerException {
		if (request.getBreedingMethodName() != null) {
			validateBreedingMethodName(request.getBreedingMethodName());
			entity.setName(request.getBreedingMethodName().trim());
		}
		if (request.getAbbreviation() != null) {
			entity.setAbbreviation(request.getAbbreviation().trim().isEmpty() ? null : request.getAbbreviation().trim());
		}
		if (request.getDescription() != null) {
			entity.setDescription(request.getDescription().trim().isEmpty() ? null : request.getDescription().trim());
		}
	}

}
