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

import egovframework.exception.MessageException;
import egovframework.util.SessionUtil;
import go.kr.project.system.group.mapper.GroupMapper;
import go.kr.project.system.group.model.GroupModifiedDataVO;
import go.kr.project.system.group.model.GroupSearchVO;
import go.kr.project.system.group.model.GroupVO;
import go.kr.project.system.group.service.GroupService;
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.List;
import java.util.Map;

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

    private final GroupMapper groupMapper;

    /**
     * 그룹 목록을 조회합니다.
     * 
     * @param paramVO 검색 조건을 담은 VO 객체
     * @return 그룹 목록
     */
    @Override
    public List<GroupVO> selectGroupList(GroupSearchVO paramVO) {
        return groupMapper.selectGroupList(paramVO);
    }

    /**
     * 그룹 목록의 총 개수를 조회합니다.
     * 
     * @param paramVO 검색 조건을 담은 VO 객체
     * @return 그룹 목록의 총 개수
     */
    @Override
    public int selectGroupListTotalCount(GroupSearchVO paramVO) {
        return groupMapper.selectGroupListTotalCount(paramVO);
    }

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

        // 1. 삭제된 행 처리
        List<GroupVO> deletedRows = modifyData.getDeletedRows();
        if (deletedRows != null && !deletedRows.isEmpty()) {
            for (GroupVO groupVO : deletedRows) {
                // 삭제 전에 그룹이 사용 중인지 확인
                if (groupMapper.checkGroupInUse(groupVO.getGroupId())) {
                    // 그룹을 사용 중인 사용자 정보 조회
                    List<Map<String, Object>> usageInfo = groupMapper.getGroupUsageInfo(groupVO.getGroupId());

                    StringBuilder errorMsg = new StringBuilder("사용 중인 그룹은 삭제할 수 없습니다: " + groupVO.getGroupId());

                    if (usageInfo != null && !usageInfo.isEmpty()) {
                        errorMsg.append("\n다음 사용자가 해당 그룹을 사용 중입니다:");

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

                            errorMsg.append("\n- ").append(userNm).append(" (").append(userId).append(")");
                        }
                    }

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

                try {
                    // 그룹-역할 매핑 정보 삭제
                    groupMapper.deleteGroupRoles(groupVO.getGroupId());

                    // 그룹 정보 삭제
                    result += groupMapper.deleteGroup(groupVO.getGroupId());
                } catch (DataIntegrityViolationException e) {
                    // 외래키 제약조건 위반 예외 처리
                    // 그룹에 연결된 다른 데이터가 있을 경우 삭제할 수 없음
                    log.error("외래키 제약조건 위반 에러 발생: {}", e.getMessage());
                    throw new MessageException("연관된 데이터 삭제 후 그룹을 삭제하시기 바랍니다");
                }
            }
        }

        // 2. 추가된 행 처리
        List<GroupVO> createdRows = modifyData.getCreatedRows();
        if (createdRows != null && !createdRows.isEmpty()) {
            for (GroupVO groupVO : createdRows) {
                // 추가 전에 그룹 ID 중복 확인
                if (groupMapper.checkGroupIdDuplicate(groupVO.getGroupId())) {
                    throw new MessageException("이미 존재하는 그룹 ID입니다: " + groupVO.getGroupId());
                }
                groupVO.setRgtr(SessionUtil.getUserId());
                groupVO.setMdfr(SessionUtil.getUserId());

                // 사용 여부가 없으면 기본값 설정
                if (groupVO.getUseYn() == null || groupVO.getUseYn().isEmpty()) {
                    groupVO.setUseYn("Y");
                }
                try {
                    // 그룹 등록 시도
                    result += groupMapper.insertGroup(groupVO);
                } catch (DuplicateKeyException e) {
                    // 중복 에러 처리
                    // 동일한 그룹 ID가 이미 존재하는 경우 중복 에러 발생
                    log.error("중복 에러 발생: {}", e.getMessage());
                    throw new MessageException("그룹 ID가 중복되었습니다");
                }
            }
        }

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

        return result;
    }
}
