package com.kamco.cd.kamcoback.postgres.core;

import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
import com.kamco.cd.kamcoback.members.dto.MembersDto;
import com.kamco.cd.kamcoback.members.dto.MembersDto.AddReq;
import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic;
import com.kamco.cd.kamcoback.members.exception.MemberException.DuplicateMemberException;
import com.kamco.cd.kamcoback.members.exception.MemberException.DuplicateMemberException.Field;
import com.kamco.cd.kamcoback.members.exception.MemberException.MemberNotFoundException;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository;
import java.time.ZonedDateTime;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MembersCoreService {

  private final MembersRepository membersRepository;

  /**
   * 관리자 계정 등록
   *
   * @param addReq
   * @return
   */
  public Long saveMembers(AddReq addReq) {
    if (membersRepository.existsByUserId(addReq.getUserId())) {
      throw new DuplicateMemberException(Field.USER_ID, addReq.getUserId());
    }

    // salt 생성, 사번이 salt
    String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(addReq.getUserId().trim());
    // 패스워드 암호화, 초기 패스워드 고정
    String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt);

    MemberEntity memberEntity = new MemberEntity();
    memberEntity.setUserId(addReq.getUserId());
    memberEntity.setUserRole(addReq.getUserRole());
    memberEntity.setTempPassword(addReq.getTempPassword()); // 임시 패스워드는 암호화 하지 않음
    memberEntity.setPassword(hashedPassword);
    memberEntity.setName(addReq.getName());
    memberEntity.setEmployeeNo(addReq.getEmployeeNo());

    return membersRepository.save(memberEntity).getId();
  }

  /**
   * 관리자 계정 수정
   *
   * @param uuid
   * @param updateReq
   */
  public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
    MemberEntity memberEntity =
      membersRepository.findByUUID(uuid).orElseThrow(MemberNotFoundException::new);

    if (StringUtils.isNotBlank(updateReq.getName())) {
      memberEntity.setName(updateReq.getName());
    }

    // 임시 패스워드는 암호화 하지 않음
    if (StringUtils.isNotBlank(updateReq.getTempPassword())) {
      memberEntity.setTempPassword(updateReq.getTempPassword());
    }

    if (StringUtils.isNotBlank(memberEntity.getEmployeeNo())) {
      memberEntity.setEmployeeNo(updateReq.getEmployeeNo());
    }

    membersRepository.save(memberEntity);
  }


  /**
   * 관리자 계정 미사용 처리
   *
   * @param uuid
   */
  public void deleteAccount(UUID uuid) {
    MemberEntity memberEntity =
      membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());

    memberEntity.setStatus("INACTIVE");
    memberEntity.setUpdatedDttm(ZonedDateTime.now());
    membersRepository.save(memberEntity);
  }


  /**
   * 패스워드 변경
   *
   * @param id
   */
  public void resetPassword(Long id, MembersDto.InitReq initReq) {
    MemberEntity memberEntity =
      membersRepository.findById(id).orElseThrow(() -> new MemberNotFoundException());

    String salt =
      BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
    // 패스워드 암호화
    String hashedPassword = BCrypt.hashpw(initReq.getPassword(), salt);

    memberEntity.setPassword(hashedPassword);
    memberEntity.setStatus("ACTIVE");
    memberEntity.setUpdatedDttm(ZonedDateTime.now());
    membersRepository.save(memberEntity);
  }
  //

  /**
   * 회원목록 조회
   *
   * @param searchReq
   * @return
   */
  public Page<Basic> findByMembers(MembersDto.SearchReq searchReq) {
    return membersRepository.findByMembers(searchReq);
  }

  /**
   * 최초 로그인 저장 마지막 로그인 저장
   *
   * @param uuid
   */
  public void saveLogin(UUID uuid) {
    MemberEntity memberEntity =
      membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());

    if (memberEntity.getFirstLoginDttm() == null) {
      memberEntity.setFirstLoginDttm(ZonedDateTime.now());
    }
    memberEntity.setLastLoginDttm(ZonedDateTime.now());
    memberEntity.setLoginFailCount(0);
    membersRepository.save(memberEntity);
  }

  /**
   * 로그인 실패시 상태 저장
   *
   * @param uuid
   */
  public void loginFail(UUID uuid) {
    MemberEntity memberEntity =
      membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());

    int failCnt = memberEntity.getLoginFailCount() + 1;
    if (failCnt >= 5) {
      memberEntity.setStatus("INACTIVE");
    }

    memberEntity.setLoginFailCount(failCnt);
    membersRepository.save(memberEntity);
  }
}
