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

import com.kamco.cd.kamcoback.members.dto.MembersDto;
import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMemberEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class MembersRepositoryImpl implements MembersRepositoryCustom {

  private final JPAQueryFactory queryFactory;
  private final QMemberEntity memberEntity = QMemberEntity.memberEntity;

  /**
   * 사용자 ID 조회
   *
   * @param userId
   * @return
   */
  @Override
  public boolean existsByUserId(String userId) {
    return queryFactory
            .selectOne()
            .from(memberEntity)
            .where(memberEntity.userId.eq(userId))
            .fetchFirst()
        != null;
  }

  /**
   * 사용자 사번 조회
   *
   * @param employeeNo
   * @return
   */
  @Override
  public boolean existsByEmployeeNo(String employeeNo) {
    return queryFactory
            .selectOne()
            .from(memberEntity)
            .where(memberEntity.employeeNo.eq(employeeNo))
            .fetchFirst()
        != null;
  }

  /**
   * 사용자 조회 user id
   *
   * @param userId
   * @return
   */
  @Override
  public Optional<MemberEntity> findByUserId(String userId) {
    return Optional.ofNullable(
        queryFactory.selectFrom(memberEntity).where(memberEntity.userId.eq(userId)).fetchOne());
  }

  /**
   * 사용자 조회 employeed no
   *
   * @param employeeNo
   * @return
   */
  @Override
  public Optional<MemberEntity> findByEmployeeNo(String employeeNo) {
    return Optional.ofNullable(
        queryFactory
            .selectFrom(memberEntity)
            .where(memberEntity.employeeNo.eq(employeeNo))
            .fetchOne());
  }

  /**
   * 회원정보 목록 조회
   *
   * @param searchReq
   * @return
   */
  @Override
  public Page<Basic> findByMembers(MembersDto.SearchReq searchReq) {
    Pageable pageable = searchReq.toPageable();
    BooleanBuilder builder = new BooleanBuilder();

    // 검색어
    if (StringUtils.isNotBlank(searchReq.getKeyword())) {
      String contains = "%" + searchReq.getKeyword() + "%";

      builder.and(
          memberEntity
              .name
              .likeIgnoreCase(contains)
              .or(memberEntity.userId.likeIgnoreCase(contains))
              .or(memberEntity.employeeNo.likeIgnoreCase(contains)));
    }

    // 권한
    if (StringUtils.isNotBlank(searchReq.getUserRole())) {
      builder.and(memberEntity.userRole.eq(searchReq.getUserRole()));
    }

    List<MembersDto.Basic> content =
        queryFactory
            .select(
                Projections.constructor(
                    MembersDto.Basic.class,
                    memberEntity.id,
                    memberEntity.uuid,
                    memberEntity.userRole,
                    memberEntity.name,
                    memberEntity.employeeNo,
                    memberEntity.status,
                    memberEntity.createdDttm,
                    memberEntity.firstLoginDttm,
                    memberEntity.lastLoginDttm,
                    memberEntity.statusChgDttm,
                    memberEntity.pwdResetYn))
            .from(memberEntity)
            .where(builder)
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .orderBy(memberEntity.createdDttm.desc())
            .fetch();

    long total =
        Optional.ofNullable(
                queryFactory
                    .select(memberEntity.count())
                    .from(memberEntity)
                    .where(builder)
                    .fetchOne())
            .orElse(0L);
    return new PageImpl<>(content, pageable, total);
  }

  /**
   * 사용자 ID 조회 UUID
   *
   * @param uuid
   * @return
   */
  @Override
  public Optional<MemberEntity> findByUUID(UUID uuid) {
    return Optional.ofNullable(
        queryFactory.selectFrom(memberEntity).where(memberEntity.uuid.eq(uuid)).fetchOne());
  }
}
