package com.oguerreiro.resilient.repository;

import java.math.BigDecimal;
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.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import com.oguerreiro.resilient.domain.Organization;
import com.oguerreiro.resilient.domain.OutputData;
import com.oguerreiro.resilient.domain.PeriodVersion;
import com.oguerreiro.resilient.domain.enumeration.UnitValueType;

/**
 * Spring Data JPA repository for the OutputData entity.
 */
@Repository
public interface OutputDataRepository extends ResilientJpaRepository<OutputData, Long>, OutputDataRepositoryExtended {
  /* Interface ResilientJpaRepository eager fetching Override methods */
  /* **************************************************************** */
  @Override
  @Query(value = "select outputData from OutputData outputData left join fetch outputData.variable left join fetch outputData.period left join fetch outputData.periodVersion left join fetch outputData.baseUnit", countQuery = "select count(outputData) from OutputData outputData")
  Page<OutputData> findAllWithEagerRelationships(Pageable pageable);

  @Override
  @Query("select outputData from OutputData outputData left join fetch outputData.variable left join fetch outputData.period left join fetch outputData.periodVersion left join fetch outputData.baseUnit")
  List<OutputData> findAllWithEagerRelationships();

  @Override
  @Query("select outputData from OutputData outputData left join fetch outputData.variable left join fetch outputData.period left join fetch outputData.periodVersion left join fetch outputData.baseUnit where outputData.id =:id")
  Optional<OutputData> findOneWithEagerRelationships(@Param("id") Long id);

  /* Custom OutputDataRepository methods */
  /* *********************************** */
  @Modifying
  @Query("delete from OutputData o where o.periodVersion = :periodVersion")
  void deleteAllByPeriodVersion(@Param("periodVersion") PeriodVersion periodVersion);

  /**
   * Output's with value type {@link UnitValueType#STRING} will be ignored in the query
   */
  @Query("SELECT SUM(od.value) from OutputData od where od.baseUnit.unitType.valueType!=com.oguerreiro.resilient.domain.enumeration.UnitValueType.STRING and od.owner=:organization and od.periodVersion=:periodVersion and od.variable.code LIKE :variableCode")
  BigDecimal sumAllOutputsFor(@Param("organization") Organization organization,
      @Param("periodVersion") PeriodVersion periodVersion, @Param("variableCode") String variableCode);

  /**
   * Output's with value type {@link UnitValueType#STRING} will be ignored in the query
   */
  @Query(value = "SELECT SUM(od.value) from OutputData od where od.baseUnit.unitType.valueType!=com.oguerreiro.resilient.domain.enumeration.UnitValueType.STRING and od.owner=:organization and od.period=:periodVersion and od.variable.baseUnit.code=:unitCode", nativeQuery = true)
  BigDecimal sumAllOutputsForUnit(@Param("organization") Organization organization,
      @Param("periodVersion") PeriodVersion periodVersion, @Param("unitCode") String unitCode);

  @Query("SELECT o FROM OutputData o WHERE o.periodVersion.id=:periodVersionId ORDER BY o.period.name, o.owner.code, o.variable.code")
  Stream<OutputData> streamAll(@Param("periodVersionId") Long periodVersionId);
}
