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

import static com.kamco.cd.kamcoback.postgres.entity.QCommonCodeEntity.commonCodeEntity;

import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
import com.kamco.cd.kamcoback.postgres.entity.QCommonCodeEntity;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class CommonCodeRepositoryImpl implements CommonCodeRepositoryCustom {

  private final JPAQueryFactory queryFactory;

  @Override
  public Optional<CommonCodeEntity> findByCodeId(Long id) {
    return Optional.ofNullable(
        queryFactory.selectFrom(commonCodeEntity).where(commonCodeEntity.id.eq(id)).fetchOne());
  }

  @Override
  public Optional<CommonCodeEntity> findByCode(String code) {
    QCommonCodeEntity child = new QCommonCodeEntity("child");
    return Optional.ofNullable(
        queryFactory
            .selectFrom(commonCodeEntity)
            .leftJoin(commonCodeEntity.children, child)
            .on(child.deleted.isFalse().or(child.deleted.isNull()))
            .where(
                commonCodeEntity.parent.isNull(),
                commonCodeEntity.code.eq(code),
                commonCodeEntity.used.isTrue(),
                commonCodeEntity.deleted.isFalse().or(commonCodeEntity.deleted.isNull()))
            .orderBy(child.order.asc())
            .fetchOne());
  }

  @Override
  public List<CommonCodeEntity> findByAll() {
    QCommonCodeEntity child = new QCommonCodeEntity("child");
    return queryFactory
        .selectFrom(commonCodeEntity)
        .leftJoin(commonCodeEntity.children, child)
        .on(child.deleted.isFalse().or(child.deleted.isNull()))
        .where(
            commonCodeEntity.parent.isNull(),
            commonCodeEntity.deleted.isFalse().or(commonCodeEntity.deleted.isNull()))
        .orderBy(commonCodeEntity.order.asc(), child.order.asc())
        .fetch();
  }

  //  @Override
  //  public void updateOrder(CommonCodeDto.OrderReq req) {
  //    Map<Long, Integer> orderMap =
  //        req.getOrders().stream()
  //            .collect(Collectors.toMap(OrderReqDetail::getId, OrderReqDetail::getOrder));
  //
  //    List<CommonCodeEntity> entity = findAllByIds(orderMap.keySet());
  //
  //    entity.forEach(
  //        commonCodeEntity -> {
  //          Integer order = orderMap.get(commonCodeEntity.getId());
  //          if (order != null) {
  //            commonCodeEntity.updateOrder(order);
  //          }
  //        });
  //  }

  @Override
  public Optional<String> getCode(String parentCodeCd, String childCodeCd) {
    QCommonCodeEntity parent = QCommonCodeEntity.commonCodeEntity;
    QCommonCodeEntity child = new QCommonCodeEntity("child");

    String result =
        queryFactory
            .select(child.name)
            .from(child)
            .join(child.parent, parent)
            .where(
                parent.code.eq(parentCodeCd).and(child.code.eq(childCodeCd)),
                child.deleted.isFalse().or(child.deleted.isNull()))
            .fetchFirst(); // 단일 결과만

    return Optional.ofNullable(result);
  }

  @Override
  public Long findByParentIdCodeExists(Long parentId, String code) {
    return queryFactory
        .select(commonCodeEntity.code.count())
        .from(commonCodeEntity)
        .where(conditionParentId(parentId), commonCodeEntity.code.eq(code))
        .fetchOne();
  }

  private BooleanExpression conditionParentId(Long parentId) {
    return parentId == null
        ? commonCodeEntity.parent.id.isNull()
        : commonCodeEntity.parent.id.eq(parentId);
  }

  private List<CommonCodeEntity> findAllByIds(Set<Long> ids) {
    return queryFactory
        .selectFrom(commonCodeEntity)
        .where(
            commonCodeEntity.id.in(ids),
            commonCodeEntity.deleted.isFalse().or(commonCodeEntity.deleted.isNull()))
        .fetch();
  }
}
