package go.kr.project.system.role.service.impl;

import egovframework.exception.MessageException;
import egovframework.util.SessionUtil;
import go.kr.project.system.role.mapper.RoleMapper;
import go.kr.project.system.role.model.RoleModifiedDataVO;
import go.kr.project.system.role.model.RoleSearchVO;
import go.kr.project.system.role.model.RoleVO;
import go.kr.project.system.role.service.RoleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

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

/**
 * packageName    : go.kr.project.system.role.service.impl
 * fileName       : RoleServiceImpl
 * author         : 시스템 관리자
 * date           : 2023-06-01
 * description    : 역할 관련 비즈니스 로직을 처리하는 서비스 구현체
 * ===========================================================
 * DATE              AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2023-06-01        시스템 관리자       최초 생성
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends EgovAbstractServiceImpl implements RoleService {

    private final RoleMapper roleMapper;

    /**
     * 역할 정보를 조회합니다.
     * 
     * @param roleId 역할 ID
     * @return 역할 정보
     */
    @Override
    public RoleVO selectRole(String roleId) {
        return roleMapper.selectRole(roleId);
    }

    /**
     * 역할 목록을 조회합니다.
     * 
     * @param paramVO 검색 조건을 담은 VO 객체
     * @return 역할 목록
     */
    @Override
    public List<RoleVO> selectRoleList(RoleSearchVO paramVO) {
        return roleMapper.selectRoleList(paramVO);
    }

    /**
     * 역할 목록의 총 개수를 조회합니다.
     * 
     * @param paramVO 검색 조건을 담은 VO 객체
     * @return 역할 목록의 총 개수
     */
    @Override
    public int selectRoleListTotalCount(RoleSearchVO paramVO) {
        return roleMapper.selectRoleListTotalCount(paramVO);
    }

    /**
     * 여러 역할 정보를 일괄 저장합니다.
     * 
     * @param modifyData 저장할 역할 정보 목록
     * @return 저장된 행의 수
     * @throws MessageException 역할이 사용 중이거나 역할 ID가 중복되는 경우, 외래키 제약조건 위반 시 발생
     */
    @Override
    public int saveRoles(RoleModifiedDataVO modifyData) {

        int result = 0;

        // 1. 삭제된 행 처리
        List<RoleVO> deletedRows = modifyData.getDeletedRows();
        if (deletedRows != null && !deletedRows.isEmpty()) {
            for( RoleVO roleVO : deletedRows ){
                // 삭제 전에 역할이 사용 중인지 확인
                if (roleMapper.checkRoleInUse(roleVO.getRoleId())) {
                    // 역할이 사용 중인 그룹 정보와 사용자 정보 조회
                    List<Map<String, Object>> usageInfo = roleMapper.getRoleUsageInfo(roleVO.getRoleId());

                    StringBuilder errorMsg = new StringBuilder("사용 중인 역할은 삭제할 수 없습니다: " + roleVO.getRoleId());

                    if (usageInfo != null && !usageInfo.isEmpty()) {
                        errorMsg.append("\n다음 그룹에서 사용 중입니다:");

                        // 그룹별로 정보 정리
                        Map<String, StringBuilder> groupUsers = new HashMap<>();

                        for (Map<String, Object> info : usageInfo) {
                            String userGroupId = (String) info.get("GROUP_ID");
                            String groupNm = (String) info.get("GROUP_NM");
                            String userId = (String) info.get("USER_ID");
                            String userNm = (String) info.get("USER_NM");

                            String groupKey = userGroupId + " (" + groupNm + ")";

                            if (!groupUsers.containsKey(groupKey)) {
                                groupUsers.put(groupKey, new StringBuilder());
                            }

                            if (userId != null && userNm != null) {
                                if (groupUsers.get(groupKey).length() > 0) {
                                    groupUsers.get(groupKey).append(", ");
                                }
                                groupUsers.get(groupKey).append(userNm).append(" (").append(userId).append(")");
                            }
                        }

                        // 그룹별 사용자 정보 추가
                        for (Map.Entry<String, StringBuilder> entry : groupUsers.entrySet()) {
                            errorMsg.append("\n- 그룹: ").append(entry.getKey());
                            if (entry.getValue().length() > 0) {
                                errorMsg.append("\n  사용자: ").append(entry.getValue());
                            }
                        }
                    }

                    throw new MessageException(errorMsg.toString());
                }

                try {
                    // 역할-메뉴 매핑 정보 삭제
                    roleMapper.deleteRoleMenus(roleVO.getRoleId());
                    
                    // 역할 정보 삭제
                    result += roleMapper.deleteRole(roleVO.getRoleId());
                } catch (DataIntegrityViolationException e) {
                    // 외래키 제약조건 위반 예외 처리
                    // 역할에 연결된 다른 데이터가 있을 경우 삭제할 수 없음
                    log.error("외래키 제약조건 위반 에러 발생: {}", e.getMessage());
                    throw new MessageException("연관된 데이터 삭제 후 역할을 삭제하시기 바랍니다");
                }
            }
        }

        // 2. 추가된 행 처리
        List<RoleVO> createdRows = modifyData.getCreatedRows();
        if (createdRows != null && !createdRows.isEmpty()) {
            for( RoleVO roleVO : createdRows ){
                // 추가 전에 역할 ID 중복 확인
                if (roleMapper.checkRoleIdDuplicate(roleVO.getRoleId())) {
                    throw new MessageException("이미 존재하는 역할 ID입니다: " + roleVO.getRoleId());
                }
                roleVO.setRgtr(SessionUtil.getUserId());
                roleVO.setMdfr(SessionUtil.getUserId());
                // 사용 여부가 없으면 기본값 설정
                if (roleVO.getUseYn() == null || roleVO.getUseYn().isEmpty()) {
                    roleVO.setUseYn("Y");
                }
                try {
                    // 역할 등록 시도
                    result += roleMapper.insertRole(roleVO);
                } catch (DuplicateKeyException e) {
                    // 중복 에러 처리
                    // 동일한 역할 ID가 이미 존재하는 경우 중복 에러 발생
                    log.error("중복 에러 발생: {}", e.getMessage());
                    throw new MessageException("역할 ID가 중복되었습니다");
                }
            }
        }

        // 3. 수정된 행 처리
        List<RoleVO> updatedRows = modifyData.getUpdatedRows();
        if (updatedRows != null && !updatedRows.isEmpty()) {
            for( RoleVO roleVO : updatedRows ){
                // 등록자가 없으면 기본값 설정
                if (roleVO.getMdfr() == null || roleVO.getMdfr().isEmpty()) {
                    roleVO.setMdfr(SessionUtil.getUserId());
                }
                // 사용 여부가 없으면 기본값 설정
                if (roleVO.getUseYn() == null || roleVO.getUseYn().isEmpty()) {
                    roleVO.setUseYn("Y");
                }
                try {
                    // 역할 수정 시도
                    result += roleMapper.updateRole(roleVO);
                } catch (DuplicateKeyException e) {
                    // 중복 에러 처리
                    // 수정 시 다른 역할과 ID가 중복되는 경우 에러 발생
                    log.error("중복 에러 발생: {}", e.getMessage());
                    throw new MessageException("역할 ID가 중복되었습니다");
                }
            }
        }

        return result;
    }

}
