package com.bio.bio_backend.domain.user.member.service;

import com.bio.bio_backend.domain.user.member.dto.MemberDto;
import com.bio.bio_backend.domain.user.member.entity.Member;
import com.bio.bio_backend.domain.user.member.enums.MemberRole;
import com.bio.bio_backend.domain.user.member.mapper.MemberMapper;
import com.bio.bio_backend.domain.user.member.repository.MemberRepository;
import com.bio.bio_backend.global.exception.ApiException;
import com.bio.bio_backend.global.constants.ApiResponseCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

import static com.bio.bio_backend.global.utils.OidUtil.generateOid;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
public class MemberServiceImpl implements MemberService {

    private final MemberMapper memberMapper;  // MapStruct Mapper 사용
    private final MemberRepository memberRepository;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
        // JPA 레파지토리를 사용하여 회원 조회
        Member member = memberRepository.findByUserId(id)
                .orElseThrow(() -> new UsernameNotFoundException("User not found with id : " + id));
        
        // MapStruct를 사용하여 Member 엔티티를 MemberDto로 변환
        MemberDto memberDto = memberMapper.toMemberDto(member);
        
        return memberDto;
    }

    @Override
    @Transactional
    public MemberDto createMember(MemberDto memberDTO) {
        // userId 중복 체크
        if (memberRepository.existsByUserId(memberDTO.getUserId())) {
            throw new ApiException(ApiResponseCode.USER_ID_DUPLICATE);
        }
        
        Member member = Member.builder()
                .userId(memberDTO.getUserId())
                .password(bCryptPasswordEncoder.encode(memberDTO.getPassword()))
                .role(MemberRole.getDefault())
                .build();

        Long oid = generateOid();
        member.setOid(oid);
        member.setCreatedOid(oid);
        
        Member savedMember = memberRepository.save(member);
        
        return memberMapper.toMemberDto(savedMember);
    }

    @Override
    @Transactional
    public void updateRefreshToken(MemberDto memberDTO) {
        // JPA를 사용하여 refresh token 업데이트
        Member member = memberRepository.findByUserId(memberDTO.getUserId())
                .orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + memberDTO.getUserId()));
        
        member.setRefreshToken(memberDTO.getRefreshToken());
        memberRepository.save(member);
    }

    @Override
    public String getRefreshToken(String id) {
        Member member = memberRepository.findByUserId(id)
                .orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + id));
        
        return member.getRefreshToken();
    }

    @Override
    @Transactional
    public int deleteRefreshToken(String id) {
        Member member = memberRepository.findByUserId(id)
                .orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + id));
        
        member.setRefreshToken(null);
        memberRepository.save(member);
        return 1; // 성공 시 1 반환
    }

    @Override
    public List<MemberDto> selectMemberList(Map<String, String> params) {
        // JPA를 사용하여 회원 목록 조회 (간단한 구현)
        List<Member> members = memberRepository.findAll();
        
        // MapStruct를 사용하여 Member 엔티티 리스트를 MemberDto 리스트로 변환
        return memberMapper.toMemberDtoList(members);
    }

    @Override
    public MemberDto selectMember(long seq) {
        // JPA 레파지토리를 사용하여 회원 조회
        Member member = memberRepository.findById(seq)
                .orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. seq: " + seq));
        
        // MapStruct를 사용하여 Member 엔티티를 MemberDto로 자동 변환
        return memberMapper.toMemberDto(member);
    }

    @Override
    @Transactional
    public int updateMember(MemberDto memberDto) {
        Member member = memberRepository.findByUserId(memberDto.getUserId())
                .orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + memberDto.getUserId()));
        
        // 비밀번호가 변경된 경우 암호화
        if (memberDto.getPassword() != null && !memberDto.getPassword().isEmpty()) {
            member.setPassword(bCryptPasswordEncoder.encode(memberDto.getPassword()));
        }
        
        member.setRole(memberDto.getRole());
        member.setUseFlag(memberDto.getUseFlag());
        
        memberRepository.save(member);
        return 1; // 성공 시 1 반환
    }

    @Override
    @Transactional
    public int deleteMember(MemberDto memberDto) {
        Member member = memberRepository.findByUserId(memberDto.getUserId())
                .orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + memberDto.getUserId()));

        member.setUseFlag(false);
        
        log.info("회원 삭제 처리: {}", member.toString());
        
        memberRepository.save(member);
        return 1; // 성공 시 1 반환
    }
}
