package com.oguerreiro.resilient.repository;

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

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.Organization;
import com.oguerreiro.resilient.domain.User;
import com.oguerreiro.resilient.domain.enumeration.OrganizationNature;

/**
 * Spring Data JPA repository for the Organization entity.
 */
@Repository
public interface OrganizationRepository extends ResilientJpaRepository<Organization, Long> {
  /* Interface ResilientJpaRepository eager fetching Override methods */
  /* **************************************************************** */
  @Override
  @Query(value = "select organization from Organization organization left join fetch organization.user left join fetch organization.parent left join fetch organization.organizationType order by (CASE WHEN organization.parent IS NULL THEN 0 ELSE 1 END), (CASE WHEN organization.sort IS NULL THEN 1 ELSE 0 END), organization.sort asc", countQuery = "select count(organization) from Organization organization")
  Page<Organization> findAllWithEagerRelationships(Pageable pageable);

  @Override
  @Query("select organization from Organization organization left join fetch organization.user left join fetch organization.parent left join fetch organization.organizationType order by (CASE WHEN organization.parent IS NULL THEN 0 ELSE 1 END), (CASE WHEN organization.sort IS NULL THEN 1 ELSE 0 END), organization.sort asc")
  List<Organization> findAllWithEagerRelationships();

  @Override
  @Query("select organization from Organization organization left join fetch organization.user left join fetch organization.parent left join fetch organization.organizationType where organization.id =:id")
  Optional<Organization> findOneWithEagerRelationships(@Param("id") Long id);

  @Override
  @Query("select organization from Organization organization order by (CASE WHEN organization.parent IS NULL THEN 0 ELSE 1 END), (CASE WHEN organization.sort IS NULL THEN 1 ELSE 0 END), organization.sort asc")
  List<Organization> findAll();

  /* Custom OrganizationRepository methods */
  /* ************************************* */
  Optional<Organization> findOneByUser(User user);

  @Query("select organization from Organization organization where organization.outputInventory = true and organization.organizationType.nature = com.oguerreiro.resilient.domain.enumeration.OrganizationNature.ORGANIZATION order by (CASE WHEN organization.parent IS NULL THEN 0 ELSE 1 END), (CASE WHEN organization.sort IS NULL THEN 1 ELSE 0 END), organization.sort asc")
  List<Organization> findAllOrganizationForOutput();

  Optional<Organization> findOneByCode(String code);

  @Query("""
      select organization
      from   Organization organization
      where  organization.organizationType.nature = :nature
             and (:forInput IS NULL or organization.inputInventory = :forInput)
             and (:forOutput IS NULL or organization.outputInventory = :forOutput)
      order by
             (CASE WHEN organization.parent IS NULL THEN 0 ELSE 1 END)
             , (CASE WHEN organization.sort IS NULL THEN 1 ELSE 0 END)
             , organization.sort asc
      """)
  List<Organization> findAllOrganizationByNature(@Param("nature") OrganizationNature nature,
      @Param("forInput") Boolean forInput, @Param("forOutput") Boolean forOutput);
}
