package com.bio.bio_backend.domain.base.member.repository;

import com.bio.bio_backend.domain.base.member.dto.MemberSearchCondition;
import com.bio.bio_backend.domain.base.member.entity.Member;
import com.bio.bio_backend.domain.base.member.entity.QMember;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;

/**
 * QueryDSL을 활용하여 MemberRepositoryCustom 인터페이스를 구현하는 클래스
 * 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
 */
@Repository
@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom {

    private final JPAQueryFactory queryFactory;
    private final QMember member = QMember.member;

    @Override
    public Optional<Member> findActiveMemberByUserId(String userId) {
        // 활성화된 사용자 중에서 사용자 ID로 검색
        Member foundMember = queryFactory
                .selectFrom(member)
                .where(member.userId.eq(userId)
                        .and(member.useFlag.eq(true)))
                .fetchOne();

        return Optional.ofNullable(foundMember);
    }

    @Override
    public Page<Member> findMembers(MemberSearchCondition condition, Pageable pageable) {
        BooleanBuilder builder = buildSearchConditions(condition);
        
        List<Member> members = queryFactory
                .selectFrom(member)
                .where(builder)
                .orderBy(member.createdAt.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();
        
        Long total = queryFactory
                .select(member.count())
                .from(member)
                .where(builder)
                .fetchOne();
        
        return new PageImpl<>(members, pageable, total);
    }
    
    @Override
    public List<Member> findMembers(MemberSearchCondition condition) {
        return queryFactory
                .selectFrom(member)
                .where(buildSearchConditions(condition))
                .orderBy(member.createdAt.desc())
                .fetch();
    }
    
    /**
     * 검색 조건들을 조합하여 BooleanBuilder 생성
     */
    private BooleanBuilder buildSearchConditions(MemberSearchCondition condition) {
        BooleanBuilder builder = new BooleanBuilder();
        
        // 기본 조건: useFlag = true (활성화된 회원만 조회)
        builder.and(member.useFlag.eq(true));
        
        // 사용자 ID (정확 일치)
        if (StringUtils.hasText(condition.getUserId())) {
            builder.and(member.userId.eq(condition.getUserId()));
        }
        
        // 이름 (부분 일치)
        if (StringUtils.hasText(condition.getName())) {
            builder.and(member.name.containsIgnoreCase(condition.getName()));
        }
        
        // 이메일 (부분 일치)
        if (StringUtils.hasText(condition.getEmail())) {
            builder.and(member.email.containsIgnoreCase(condition.getEmail()));
        }
        
        // 통합 검색 키워드 (이름, 이메일, 사용자ID에서 검색)
        if (StringUtils.hasText(condition.getSearchKeyword())) {
            String keyword = condition.getSearchKeyword();
            builder.and(member.name.containsIgnoreCase(keyword)
                    .or(member.email.containsIgnoreCase(keyword))
                    .or(member.userId.containsIgnoreCase(keyword)));
        }
        

        // 생성일 범위
        if (StringUtils.hasText(condition.getCreatedDateFrom())) {
            LocalDate fromDate = LocalDate.parse(condition.getCreatedDateFrom(), DateTimeFormatter.ISO_LOCAL_DATE);
            builder.and(member.createdAt.goe(fromDate.atStartOfDay()));
        }
        if (StringUtils.hasText(condition.getCreatedDateTo())) {
            LocalDate toDate = LocalDate.parse(condition.getCreatedDateTo(), DateTimeFormatter.ISO_LOCAL_DATE);
            builder.and(member.createdAt.loe(toDate.atTime(23, 59, 59)));
        }
        
        // 마지막 로그인 범위
        if (StringUtils.hasText(condition.getLastLoginFrom())) {
            LocalDate fromDate = LocalDate.parse(condition.getLastLoginFrom(), DateTimeFormatter.ISO_LOCAL_DATE);
            builder.and(member.lastLoginAt.goe(fromDate.atStartOfDay()));
        }
        if (StringUtils.hasText(condition.getLastLoginTo())) {
            LocalDate toDate = LocalDate.parse(condition.getLastLoginTo(), DateTimeFormatter.ISO_LOCAL_DATE);
            builder.and(member.lastLoginAt.loe(toDate.atTime(23, 59, 59)));
        }
        
        return builder;
    }

}
