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.exception.MemberException;
import com.kamco.cd.kamcoback.members.exception.MemberException.MemberNotFoundException;
import com.kamco.cd.kamcoback.postgres.entity.MemberArchivedEntity;
import com.kamco.cd.kamcoback.postgres.entity.MemberArchivedEntityId;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import com.kamco.cd.kamcoback.postgres.entity.MemberRoleEntity;
import com.kamco.cd.kamcoback.postgres.entity.MemberRoleEntityId;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersArchivedRepository;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository;
import com.kamco.cd.kamcoback.postgres.repository.members.MembersRoleRepository;
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.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MembersCoreService {

  private final MembersRepository membersRepository;
  private final MembersRoleRepository memberRoleRepository;
  private final MembersArchivedRepository memberArchivedRepository;

  @Value("${member.init_password}")
  private String password;

  /**
   * 회원가입
   *
   * @param addReq
   * @return
   */
  public Long saveMembers(MembersDto.AddReq addReq) {
    if (membersRepository.existsByEmployeeNo(addReq.getEmployeeNo())) {
      throw new MemberException.DuplicateMemberException(
          MemberException.DuplicateMemberException.Field.EMPLOYEE_NO, addReq.getEmployeeNo());
    }

    if (membersRepository.existsByEmail(addReq.getEmail())) {
      throw new MemberException.DuplicateMemberException(
          MemberException.DuplicateMemberException.Field.EMAIL, addReq.getEmail());
    }

    MemberEntity memberEntity = new MemberEntity();
    memberEntity.setEmployeeNo(addReq.getEmployeeNo());
    memberEntity.setName(addReq.getName());
    memberEntity.setPassword(addReq.getPassword());
    memberEntity.setEmail(addReq.getEmail());

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

  /**
   * 회원정보 수정
   *
   * @param uuid
   * @param updateReq
   */
  public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
    MemberEntity memberEntity =
        membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());

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

    if (StringUtils.isNotBlank(updateReq.getName())) {
      memberEntity.setName(updateReq.getName());
    }
    if (StringUtils.isNotBlank(updateReq.getPassword())) {
      memberEntity.setPassword(updateReq.getPassword());
    }
    if (StringUtils.isNotBlank(updateReq.getEmail())) {
      memberEntity.setEmail(updateReq.getEmail());
    }

    membersRepository.save(memberEntity);
  }

  /**
   * 역할 추가
   *
   * @param rolesDto
   */
  public void saveRoles(MembersDto.RolesDto rolesDto) {

    MemberEntity memberEntity =
        membersRepository
            .findByUUID(rolesDto.getUuid())
            .orElseThrow(() -> new MemberNotFoundException());

    if (memberRoleRepository.findByUuidAndRoleName(rolesDto)) {
      throw new MemberException.DuplicateMemberException(
          MemberException.DuplicateMemberException.Field.DEFAULT, "중복된 역할이 있습니다.");
    }

    MemberRoleEntityId memberRoleEntityId = new MemberRoleEntityId();
    memberRoleEntityId.setMemberUuid(rolesDto.getUuid());
    memberRoleEntityId.setRoleName(rolesDto.getRoleName());

    MemberRoleEntity memberRoleEntity = new MemberRoleEntity();
    memberRoleEntity.setId(memberRoleEntityId);
    memberRoleEntity.setMemberUuid(memberEntity);
    memberRoleEntity.setCreatedDttm(ZonedDateTime.now());
    memberRoleRepository.save(memberRoleEntity);
  }

  /**
   * 역할 삭제
   *
   * @param rolesDto
   */
  public void deleteRoles(MembersDto.RolesDto rolesDto) {
    MemberEntity memberEntity =
        membersRepository
            .findByUUID(rolesDto.getUuid())
            .orElseThrow(() -> new MemberNotFoundException());

    MemberRoleEntityId memberRoleEntityId = new MemberRoleEntityId();
    memberRoleEntityId.setMemberUuid(rolesDto.getUuid());
    memberRoleEntityId.setRoleName(rolesDto.getRoleName());

    MemberRoleEntity memberRoleEntity = new MemberRoleEntity();
    memberRoleEntity.setId(memberRoleEntityId);
    memberRoleEntity.setMemberUuid(memberEntity);

    memberRoleRepository.delete(memberRoleEntity);
  }

  /**
   * 상태 수정
   *
   * @param statusDto
   */
  public void updateStatus(UUID uuid, MembersDto.StatusDto statusDto) {
    MemberEntity memberEntity =
        membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());

    memberEntity.setStatus(statusDto.getStatus());
    memberEntity.setUpdatedDttm(ZonedDateTime.now());
    membersRepository.save(memberEntity);
  }

  /**
   * 회원 탈퇴
   *
   * @param uuid
   */
  public void deleteAccount(UUID uuid) {
    MemberEntity memberEntity =
        membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());

    MemberArchivedEntityId memberArchivedEntityId = new MemberArchivedEntityId();
    memberArchivedEntityId.setUserId(memberEntity.getId());
    memberArchivedEntityId.setUuid(memberEntity.getUuid());

    MemberArchivedEntity memberArchivedEntity = new MemberArchivedEntity();
    memberArchivedEntity.setId(memberArchivedEntityId);
    memberArchivedEntity.setEmployeeNo(memberEntity.getEmployeeNo());
    memberArchivedEntity.setName(memberEntity.getName());
    memberArchivedEntity.setPassword(memberEntity.getPassword());
    memberArchivedEntity.setEmail(memberEntity.getEmail());
    memberArchivedEntity.setStatus(memberEntity.getStatus());
    memberArchivedEntity.setCreatedDttm(memberEntity.getCreatedDttm());
    memberArchivedEntity.setArchivedDttm(ZonedDateTime.now());
    memberArchivedRepository.save(memberArchivedEntity);

    memberEntity.setStatus("ARCHIVED");
    memberEntity.setName("**********");
    memberEntity.setEmployeeNo("**********");
    memberEntity.setPassword("**********");
    memberEntity.setEmail("**********");
    memberEntity.setUpdatedDttm(ZonedDateTime.now());
    membersRepository.save(memberEntity);
  }

  /**
   * 패스워드 초기화
   *
   * @param id
   */
  public void resetPassword(Long id) {
    MemberEntity memberEntity =
        membersRepository.findById(id).orElseThrow(() -> new MemberNotFoundException());

    String salt =
        BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
    // 패스워드 암호화, 초기 패스워드 고정
    String hashedPassword = BCrypt.hashpw(password, salt);

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

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