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

import com.kamco.cd.kamcoback.common.enums.RoleType;
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.kamco.cd.kamcoback.postgres.entity.QMemberRoleEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.ArrayList;
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;
  private final QMemberRoleEntity memberRoleEntity = QMemberRoleEntity.memberRoleEntity;

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

  /**
   * 이메일 조회
   *
   * @param email
   * @return
   */
  @Override
  public boolean existsByEmail(String email) {
    return queryFactory
            .selectOne()
            .from(memberEntity)
            .where(memberEntity.email.eq(email))
            .fetchFirst()
        != null;
  }

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

    if (StringUtils.isNotBlank(searchReq.getField())) {
      switch (searchReq.getField()) {
        case "name" ->
            builder.and(memberEntity.name.containsIgnoreCase(searchReq.getKeyword().trim()));
        case "email" ->
            builder.and(memberEntity.email.containsIgnoreCase(searchReq.getKeyword().trim()));
        case "employeeNo" ->
            builder.and(memberEntity.employeeNo.containsIgnoreCase(searchReq.getKeyword().trim()));
      }
    }

    List<String> roles = new ArrayList<>();
    // 라벨러
    if (searchReq.isLabeler()) {
      roles.add(RoleType.ROLE_LABELER.getId());
    }

    // 시스템 전체 관리자
    if (searchReq.isAdmin()) {
      roles.add(RoleType.ROLE_ADMIN.getId());
    }

    // 검수자
    if (searchReq.isReviewer()) {
      roles.add(RoleType.ROLE_REVIEWER.getId());
    }

    // 역할 in 조건 추가
    if (!roles.isEmpty()) {
      leftBuilder.and(memberRoleEntity.id.roleName.in(roles));
    }

    List<MembersDto.Basic> content =
        queryFactory
            .select(
                Projections.constructor(
                    MembersDto.Basic.class,
                    memberEntity.id,
                    memberEntity.uuid,
                    memberEntity.employeeNo,
                    memberEntity.name,
                    memberEntity.email,
                    memberEntity.status,
                    memberRoleEntity.id.roleName,
                    memberEntity.createdDttm,
                    memberEntity.updatedDttm))
            .from(memberEntity)
            .leftJoin(memberRoleEntity)
            .on(memberRoleEntity.memberUuid.uuid.eq(memberEntity.uuid).and(leftBuilder))
            .where(builder)
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .orderBy(memberEntity.createdDttm.desc())
            .fetch();

    long total =
        queryFactory
            .select(memberEntity)
            .from(memberEntity)
            .leftJoin(memberRoleEntity)
            .on(memberRoleEntity.memberUuid.uuid.eq(memberEntity.uuid).and(leftBuilder))
            .fetchCount();

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

  @Override
  public Optional<MemberEntity> findByUUID(UUID uuid) {
    return Optional.ofNullable(
        queryFactory.selectFrom(memberEntity).where(memberEntity.uuid.eq(uuid)).fetchOne());
  }

  @Override
  public Optional<MemberEntity> findByEmployeeNo(String employeeNo) {
    return Optional.ofNullable(
        queryFactory
            .selectFrom(memberEntity)
            .where(memberEntity.employeeNo.eq(employeeNo))
            .fetchOne());
  }
}
