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.Variable;

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

  @Override
  @Query("select variable from Variable variable left join fetch variable.baseUnit left join fetch variable.variableScope left join fetch variable.variableCategory left join fetch variable.variableUnits")
  List<Variable> findAllWithEagerRelationships();

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

  /* Custom VariableRepository methods */
  /* ********************************* */
  @Query("select variable from Variable variable left join fetch variable.baseUnit left join fetch variable.variableScope left join fetch variable.variableCategory left join fetch variable.variableUnits where variable.code =:code")
  Optional<Variable> findOneByCodeWithToOneRelationships(@Param("code") String code);

  @Query("select variable from Variable variable where variable.output = true and (variable.outputSingle is null OR variable.outputSingle = false)")
  List<Variable> findAllOutputNotSingle();

  @Query("select variable from Variable variable where variable.output = true and variable.outputSingle = true")
  List<Variable> findAllOutputSingle();

  @Query("""
      select  variable
      from    Variable variable
      where   variable.input = true
              and variable.inputMode IN (com.oguerreiro.resilient.domain.enumeration.InputMode.MANUAL, com.oguerreiro.resilient.domain.enumeration.InputMode.ANY)
      order by variable.name
      """)
  List<Variable> findAllForManualInput();

  @Query("SELECT v FROM Variable v WHERE v.input = :input AND v.output = :output ORDER BY v.code")
  Stream<Variable> streamAll(@Param("input") Boolean input, @Param("output") Boolean output);
}
