package com.kamco.cd.kamcoback.postgres.repository;

import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity;
import com.kamco.cd.kamcoback.postgres.entity.QAnimalEntity;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Category;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Species;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;

public class AnimalRepositoryImpl extends QuerydslRepositorySupport
    implements AnimalRepositoryCustom {

  private final JPAQueryFactory queryFactory;

  public AnimalRepositoryImpl(JPAQueryFactory queryFactory) {
    super(AnimalEntity.class);
    this.queryFactory = queryFactory;
  }

  public Optional<AnimalEntity> getAnimalByUid(Long uid) {
    QAnimalEntity animal = QAnimalEntity.animalEntity;

    return Optional.ofNullable(
        queryFactory.selectFrom(animal).where(animal.uid.eq(uid)).fetchFirst());
  }

  public Optional<AnimalEntity> getAnimalByUuid(String uuid) {
    QAnimalEntity animal = QAnimalEntity.animalEntity;

    return Optional.ofNullable(
        queryFactory.selectFrom(animal).where(animal.uuid.eq(UUID.fromString(uuid))).fetchFirst());
  }

  @Override
  public Page<AnimalEntity> listAnimal(AnimalDto.SearchReq req) {
    QAnimalEntity animal = QAnimalEntity.animalEntity;

    Pageable pageable = req.toPageable();

    List<AnimalEntity> content =
        queryFactory
            .selectFrom(animal)
            .where(
                animal.isDeleted.eq(false),
                eqCategory(animal, req.getCategory()),
                eqSpecies(animal, req.getSpecies()),
                likeName(animal, req.getName()))
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .orderBy(animal.createdDate.desc())
            .fetch();

    // count 쿼리
    Long total =
        queryFactory
            .select(animal.count())
            .from(animal)
            .where(
                animal.isDeleted.eq(false),
                eqCategory(animal, req.getCategory()),
                eqSpecies(animal, req.getSpecies()),
                likeName(animal, req.getName()))
            .fetchOne();

    return new PageImpl<>(content, pageable, total);
  }

  private BooleanExpression likeName(QAnimalEntity animal, String nameStr) {
    if (nameStr == null || nameStr.isEmpty()) {
      return null;
    }
    return animal.name.containsIgnoreCase(nameStr.trim());
  }

  private BooleanExpression eqCategory(QAnimalEntity animal, Category category) {
    if (category == null) {
      return null;
    }
    return animal.category.eq(category);
  }

  private BooleanExpression eqSpecies(QAnimalEntity animal, Species species) {
    if (species == null) {
      return null;
    }
    return animal.species.eq(species);
  }
}
