package com.oguerreiro.resilient.service.query;

import java.util.List;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

// for static metamodels
import com.oguerreiro.resilient.domain.EmissionFactor;
import com.oguerreiro.resilient.domain.EmissionFactor_;
import com.oguerreiro.resilient.repository.EmissionFactorRepository;
import com.oguerreiro.resilient.service.criteria.EmissionFactorCriteria;
import com.oguerreiro.resilient.service.dto.EmissionFactorDTO;
import com.oguerreiro.resilient.service.mapper.EmissionFactorMapper;

import jakarta.persistence.criteria.JoinType;

/**
 * Service for executing complex queries for {@link EmissionFactor} entities in the
 * database. The main input is a {@link EmissionFactorCriteria} which gets converted
 * to {@link Specification}, in a way that all the filters must apply. It
 * returns a {@link List} of {@link EmissionFactorDTO} which fulfills the criteria.
 */
@Service
@Transactional(readOnly = true)
public class EmissionFactorQueryService
    extends AbstractQueryService<EmissionFactor, EmissionFactorDTO, Long, EmissionFactorCriteria> {

  public EmissionFactorQueryService(EmissionFactorRepository emissionFactorRepository,
      EmissionFactorMapper emissionFactorMapper) {
    super(emissionFactorRepository, emissionFactorMapper);
  }

  /**
   * Function to convert {@link EmissionFactorCriteria} to a {@link Specification}
   * 
   * @param  criteria The object which holds all the filters, which the entities
   *                  should match.
   * @return          the matching {@link Specification} of the entity.
   */
  protected Specification<EmissionFactor> createSpecification(EmissionFactorCriteria criteria) {
    Specification<EmissionFactor> specification = Specification.where(null);
    if (criteria != null) {
      // This has to be called first, because the distinct method returns null
      if (criteria.getDistinct() != null) {
        specification = specification.and(distinct(criteria.getDistinct()));
      }

      if (criteria.getId() != null) {
        specification = specification.and(buildRangeSpecification(criteria.getId(), EmissionFactor_.id));
      }
      if (criteria.getValue() != null) {
        specification = specification.and(buildRangeSpecification(criteria.getValue(), EmissionFactor_.value));
      }
      if (criteria.getYear() != null) {
        specification = specification.and(buildRangeSpecification(criteria.getYear(), EmissionFactor_.year));
      }
      if (criteria.getCode() != null) {
        specification = specification.and(buildStringSpecification(criteria.getCode(), EmissionFactor_.code));
      }
      if (criteria.getName() != null) {
        specification = specification.and(buildStringSpecification(criteria.getName(), EmissionFactor_.name));
      }
      if (criteria.getUnit() != null) {
        specification = specification.and(buildStringSpecification(criteria.getUnit(), EmissionFactor_.unit));
      }
      if (criteria.getSource() != null) {
        specification = specification.and(buildStringSpecification(criteria.getSource(), EmissionFactor_.source));
      }
      if (criteria.getComments() != null) {
        specification = specification.and(buildStringSpecification(criteria.getComments(), EmissionFactor_.comments));
      }
      if (criteria.getVariableScopeId() != null) {
        specification = specification.and(buildSpecification(criteria.getVariableScopeId(),
            root -> root.join(EmissionFactor_.variableScope, JoinType.LEFT).get(ID_ATTRIBUTE_NAME)));
      }
      if (criteria.getVariableCategoryId() != null) {
        specification = specification.and(buildSpecification(criteria.getVariableCategoryId(),
            root -> root.join(EmissionFactor_.variableCategory, JoinType.LEFT).get(ID_ATTRIBUTE_NAME)));
      }
    }
    return specification;
  }
}
