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

import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
import com.kamco.cd.kamcoback.common.enums.StatusType;
import com.kamco.cd.kamcoback.common.enums.error.AuthErrorCode;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.common.utils.CommonStringUtils;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
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.dto.SignInRequest;
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.http.HttpStatus;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MembersCoreService {

  private final MembersRepository membersRepository;
  private final UserUtil userUtil;

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

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

    MemberEntity memberEntity = new MemberEntity();
    memberEntity.setUserId(addReq.getEmployeeNo());
    memberEntity.setUserRole(addReq.getUserRole());
    memberEntity.setPassword(hashedPassword);
    memberEntity.setName(addReq.getName());
    memberEntity.setEmployeeNo(addReq.getEmployeeNo());
    memberEntity.setRgstrUidl(userUtil.getId());
    memberEntity.setStatus(StatusType.PENDING.getId());

    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.getStatus())) {
      memberEntity.changeStatus(updateReq.getStatus());
    }

    if (StringUtils.isNotBlank(updateReq.getPassword())) {

      // 패스워드 유효성 검사
      if (!CommonStringUtils.isValidPassword(updateReq.getPassword())) {
        throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
      }

      String password =
          CommonStringUtils.hashPassword(updateReq.getPassword(), memberEntity.getEmployeeNo());

      memberEntity.setStatus(StatusType.PENDING.getId());
      memberEntity.setLoginFailCount(0);
      memberEntity.setPassword(password);
      memberEntity.setPwdResetYn(true);
    }
    memberEntity.setUpdtrUid(userUtil.getId());
    membersRepository.save(memberEntity);
  }

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

    // 기존 패스워드 확인
    if (!BCrypt.checkpw(initReq.getOldPassword(), memberEntity.getPassword())) {
      throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
    }

    String password =
        CommonStringUtils.hashPassword(initReq.getNewPassword(), memberEntity.getEmployeeNo());

    memberEntity.setPassword(password);
    memberEntity.setStatus(StatusType.ACTIVE.getId());
    memberEntity.setUpdatedDttm(ZonedDateTime.now());
    memberEntity.setUpdtrUid(memberEntity.getId());
    memberEntity.setPwdResetYn(false);
    membersRepository.save(memberEntity);
  }

  //

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

  /**
   * 사용자 상태 조회
   *
   * @param request
   * @return
   */
  public String getUserStatus(SignInRequest request) {
    MemberEntity memberEntity =
        membersRepository
            .findByEmployeeNo(request.getUsername())
            .orElseThrow(MemberNotFoundException::new);
    return memberEntity.getStatus();
  }

  /**
   * 최초 로그인 저장 마지막 로그인 저장
   *
   * @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 employeeNo
   * @return
   */
  public boolean existsByEmployeeNo(String employeeNo) {
    return membersRepository.existsByEmployeeNo(employeeNo);
  }
}
