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

import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx50kEntity.mapInkx50kEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity;

import com.kamco.cd.kamcoback.common.enums.CommonUseStatus;
import com.kamco.cd.kamcoback.postgres.entity.MapInkx5kEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity;
import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto;
import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto.MapList;
import com.kamco.cd.kamcoback.scene.dto.MapInkxMngDto.searchReq;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
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 MapInkx5kRepositoryImpl extends QuerydslRepositorySupport
    implements MapInkx5kRepositoryCustom {

  private final JPAQueryFactory queryFactory;

  public MapInkx5kRepositoryImpl(JPAQueryFactory queryFactory) {
    super(MapInkx5kEntity.class);
    this.queryFactory = queryFactory;
  }

  public List<MapInkx5kEntity> listGetScenes5k(List<String> codes) {
    QMapInkx5kEntity map5k = QMapInkx5kEntity.mapInkx5kEntity;

    return queryFactory
        .selectFrom(map5k)
        .where(map5k.mapidcdNo.in(codes))
        .orderBy(map5k.mapidcdNo.asc())
        .fetch();
  }

  @Override
  public Page<MapList> findMapInkxMngList(
      searchReq searchReq, CommonUseStatus useInference, String searchVal) {

    Pageable pageable = searchReq.toPageable();
    List<MapInkxMngDto.MapList> foundContent =
        queryFactory
            .select(
                Projections.constructor(
                    MapInkxMngDto.MapList.class,
                    Expressions.numberTemplate(
                        Integer.class,
                        "row_number() over(order by {0} asc)",
                        mapInkx5kEntity.mapidcdNo),
                    mapInkx5kEntity.mapidcdNo,
                    mapInkx50kEntity.mapidcdNo,
                    mapInkx5kEntity.mapidNm,
                    mapInkx5kEntity.createdDate,
                    mapInkx5kEntity.modifiedDate,
                    //          Expressions.stringTemplate("to_char({0}, 'YYYY-MM-DD')",
                    // mapInkx5kEntity.createdDate),
                    //          Expressions.stringTemplate("to_char({0}, 'YYYY-MM-DD')",
                    // mapInkx5kEntity.modifiedDate),
                    mapInkx5kEntity.useInference))
            .from(mapInkx5kEntity)
            .innerJoin(mapInkx5kEntity.mapInkx50k, mapInkx50kEntity)
            .where(searchUseInference(useInference), searchValueMapCdNm(searchVal))
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .orderBy(mapInkx5kEntity.mapidcdNo.asc())
            .fetch();

    Long countQuery =
        queryFactory
            .select(mapInkx5kEntity.count())
            .from(mapInkx5kEntity)
            .innerJoin(mapInkx5kEntity.mapInkx50k, mapInkx50kEntity)
            .where(searchUseInference(useInference), searchValueMapCdNm(searchVal))
            .fetchOne();

    return new PageImpl<>(foundContent, pageable, countQuery);
  }

  @Override
  public Long findByMapidCdNoExists(String mapidcdNo) {
    return queryFactory
        .select(mapInkx5kEntity.count())
        .from(mapInkx5kEntity)
        .where(mapInkx5kEntity.mapidcdNo.eq(mapidcdNo))
        .fetchOne();
  }

  @Override
  public Optional<MapInkx5kEntity> findByMapidCdNoInfo(String mapidcdNo) {
    return Optional.ofNullable(
        queryFactory
            .selectFrom(mapInkx5kEntity)
            .where(mapInkx5kEntity.mapidcdNo.eq(mapidcdNo))
            .fetchOne());
  }

  private BooleanExpression searchUseInference(CommonUseStatus useInference) {
    if (Objects.isNull(useInference)) {
      return null;
    }
    return mapInkx5kEntity.useInference.eq(useInference);
  }

  private BooleanExpression searchValueMapCdNm(String searchVal) {
    if (Objects.isNull(searchVal)) {
      return null;
    }
    return mapInkx5kEntity
        .mapidcdNo
        .like("%" + searchVal + "%")
        .or(mapInkx5kEntity.mapidNm.like("%" + searchVal + "%"));
  }
}
