package com.oguerreiro.resilient.repository;

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

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import com.oguerreiro.resilient.domain.EmissionFactor;

/**
 * Spring Data JPA repository for the EmissionFactor entity.
 */
@Repository
public interface EmissionFactorRepository extends ResilientJpaRepository<EmissionFactor, Long> {
  /* Interface ResilientJpaRepository eager fetching Override methods */
  /* **************************************************************** */
  @Override
  @Query(value = "select emissionFactor from EmissionFactor emissionFactor left join fetch emissionFactor.variableScope left join fetch emissionFactor.variableCategory", countQuery = "select count(emissionFactor) from EmissionFactor emissionFactor")
  Page<EmissionFactor> findAllWithEagerRelationships(Pageable pageable);

  @Override
  @Query("select emissionFactor from EmissionFactor emissionFactor left join fetch emissionFactor.variableScope left join fetch emissionFactor.variableCategory")
  List<EmissionFactor> findAllWithEagerRelationships();

  @Override
  @Query("select emissionFactor from EmissionFactor emissionFactor left join fetch emissionFactor.variableScope left join fetch emissionFactor.variableCategory where emissionFactor.id =:id")
  Optional<EmissionFactor> findOneWithEagerRelationships(@Param("id") Long id);

  /* Custom EmissionFactorRepository methods */
  /* *************************************** */
  EmissionFactor findByCodeAndYear(String code, Integer year);

  /**
   * Intended to get ONLY the first record. This will be the closest EmissionFactor for the provided year
   * 
   * @param  code
   * @param  year
   * @return
   */
  @Query("SELECT emissionFactor FROM EmissionFactor emissionFactor WHERE emissionFactor.code = :code AND emissionFactor.year<=:year ORDER BY emissionFactor.year DESC")
  List<EmissionFactor> findByCodeAndYearOrderByYear(@Param("code") String code, @Param("year") Integer year);

  @Query("SELECT e FROM EmissionFactor e WHERE e.year = :year AND e.variableScope.id=:scopeId AND (:categoryId is null OR e.variableCategory.id=:categoryId) ORDER BY e.year, e.variableScope.name, e.variableCategory.name, e.name")
  Stream<EmissionFactor> streamAll(@Param("year") Integer year, @Param("scopeId") Long scopeId,
      @Param("categoryId") Long categoryId);

  @Query("""
          SELECT ef
          FROM EmissionFactor ef
          WHERE ef.year = (
              SELECT MAX(e2.year)
              FROM EmissionFactor e2
              WHERE e2.code = ef.code
                AND e2.year <= :year
                AND e2.value <> 0
                AND (:scopeId IS NULL OR e2.variableScope.id = :scopeId)
                AND (:categoryId IS NULL OR e2.variableCategory.id = :categoryId)
          )
            AND ef.value <> 0
            AND ef.year <= :year
            AND (:scopeId IS NULL OR ef.variableScope.id = :scopeId)
            AND (:categoryId IS NULL OR ef.variableCategory.id = :categoryId)
          ORDER BY ef.code ASC
      """)
  List<EmissionFactor> findAllBySearch(@Param("year") Integer year, @Param("scopeId") Long scopeId,
      @Param("categoryId") Long categoryId);
}
