package incheon.ags.mrb.share.service.impl;

import incheon.ags.mrb.main.mapper.RecipeMapper;
import incheon.ags.mrb.main.mapper.RecipeLayerMapper;
import incheon.ags.mrb.main.vo.RecipeVO;
import incheon.ags.mrb.main.dto.RecipeDetailDTO;
import incheon.ags.mrb.share.mapper.RecipeShrnDtlMapper;
import incheon.ags.mrb.share.mapper.RecipeShrnMapper;
import incheon.ags.mrb.share.service.RecipeShrnService;
import incheon.ags.mrb.share.vo.RecipeShrnDtlVO;
import incheon.ags.mrb.share.vo.RecipeShrnVO;
import incheon.ags.mrb.share.web.dto.RecipeShareDTO;
import incheon.ags.mrb.share.web.dto.ShareTargetDTO;
import incheon.ags.mrb.main.exception.RecipeException;
import incheon.ags.mrb.main.exception.ErrorCode;
import incheon.ags.mrb.main.annotation.OwnerCheck;
import incheon.com.security.vo.LoginVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 레시피 공유 서비스 구현체
 * - 레시피 공유 요청 및 승인 관리
 */
@Slf4j
@Service("recipeShrnService")
@RequiredArgsConstructor
public class RecipeShrnServiceImpl extends EgovAbstractServiceImpl implements RecipeShrnService {

    private final RecipeShrnMapper recipeShrnMapper;
    private final RecipeShrnDtlMapper recipeShrnDtlMapper;
    private final RecipeLayerMapper recipeLayerMapper;
    private final RecipeMapper recipeMapper;

    /**
     * 레시피 공유 목록 조회
     */
    @Override
    public Map<String, Object> getRecipeShrnList(RecipeShrnVO recipeShrnVO) throws Exception {
        log.debug("레시피 공유 목록 조회 - 검색 조건: {}", recipeShrnVO);
        // 목록 조회 (총 건수 포함)
        List<RecipeShrnVO> list = recipeShrnMapper.selectRecipeShrnList(recipeShrnVO);

        // 총 건수 추출 (첫 번째 항목에서)
        int totalCount = list.isEmpty() ? 0 : list.get(0).getTotalCount();
        int totalPages = (int) Math.ceil((double) totalCount / recipeShrnVO.getRecordCountPerPage());

        // 각 공유 요청의 공유 대상 ID 목록 추가
        for (RecipeShrnVO shrn : list) {
            // recipe_shrn_dtl 테이블에서 공유 대상 목록 조회
            List<RecipeShrnDtlVO> dtlList = this.getRecipeShrnDtlListByShrnId(shrn.getShrnId());

            // 공유 대상 이름 목록 (부서-이름 형식)
            List<String> shareTargetNames = new ArrayList<>();

            for (RecipeShrnDtlVO dtl : dtlList) {
                String name = dtl.getShrnTrgtNm();
                String deptNm = dtl.getShrnTrgtDeptNm();
                String displayName;
                if (name != null && !name.isEmpty()) {
                    displayName = (deptNm != null && !deptNm.isEmpty()) ? deptNm + "-" + name : name;
                } else {
                    displayName = dtl.getShrnTrgtId();
                }
                if (displayName != null) {
                    shareTargetNames.add(displayName);
                }
            }

            shrn.setShareTargetNames(shareTargetNames);
        }

        // 결과 맵 구성
        Map<String, Object> result = new HashMap<>();
        result.put("list", list);
        result.put("totalCount", totalCount);
        result.put("pageIndex", recipeShrnVO.getPageIndex());
        result.put("recordCountPerPage", recipeShrnVO.getRecordCountPerPage());
        result.put("totalPages", totalPages);

        log.debug("레시피 공유 목록 조회 완료 - 총 {}건", totalCount);
        return result;
    }

    /**
     * 레시피 공유 상세 조회
     */
    @Override
    public RecipeShrnVO getRecipeShrnDetail(Integer shrnId) throws Exception {
        log.debug("레시피 공유 상세 조회 - shrnId: {}", shrnId);

        if (shrnId == null) {
            throw new IllegalArgumentException("공유 ID는 필수입니다");
        }

        RecipeShrnVO recipeShrnVO = recipeShrnMapper.selectRecipeShrnDetail(shrnId);

        if (recipeShrnVO == null) {
            throw new IllegalArgumentException("해당 공유 요청을 찾을 수 없습니다");
        }

        log.debug("레시피 공유 상세 조회 완료 - recipeId: {}", recipeShrnVO.getRecipeId());
        return recipeShrnVO;
    }

    /**
     * 레시피 공유 승인 상태 수정
     */
    @Override
    @Transactional
    public void updateRecipeShrnStatus(Integer shrnId, String aprvStts) throws Exception {
        log.debug("레시피 공유 승인 상태 수정 - shrnId: {}, aprvStts: {}", shrnId, aprvStts);

        // 유효성 검증
        if (shrnId == null) {
            throw new IllegalArgumentException("공유 ID는 필수입니다");
        }

        if (aprvStts == null || aprvStts.isEmpty()) {
            throw new IllegalArgumentException("승인 상태는 필수입니다");
        }

        if (!aprvStts.matches("^[PYN]$")) {
            throw new IllegalArgumentException("승인 상태는 P(대기), Y(승인), N(거부) 중 하나여야 합니다");
        }

        // 공유 요청 존재 여부 확인
        RecipeShrnVO existingShrn = recipeShrnMapper.selectRecipeShrnDetail(shrnId);
        if (existingShrn == null) {
            throw new IllegalArgumentException("해당 공유 요청을 찾을 수 없습니다");
        }

        // 상태 수정
        RecipeShrnVO updateVO = new RecipeShrnVO();
        updateVO.setShrnId(shrnId);
        updateVO.setAprvStts(aprvStts);
        updateVO.setLastMdfcnId("system"); // 시스템 수정자 ID

        recipeShrnMapper.updateRecipeShrnStatus(updateVO);

        log.debug("레시피 공유 승인 상태 수정 완료 - shrnId: {}", shrnId);
    }

    /**
     * 레시피 공유 요청 삭제
     */
    @Override
    @Transactional
    @OwnerCheck(allowShared = false, message = "레시피 공유 삭제 권한이 없습니다")
    public void deleteRecipeShrn(Integer recipeId, LoginVO loginUser, Integer shareId) throws Exception {
        log.debug("레시피 공유 요청 삭제 - recipeId: {}, shareId: {}, userId: {}", recipeId, shareId, loginUser.getUserId());

        // 공유 요청 존재 여부 확인
        RecipeShrnVO existingShrn = recipeShrnMapper.selectRecipeShrnDetail(shareId);
        if (existingShrn == null) {
            throw new IllegalArgumentException("해당 공유 요청을 찾을 수 없습니다");
        }

        // 1. 먼저 자식 테이블(recipe_shrn_dtl)의 레코드 삭제
        recipeShrnDtlMapper.deleteRecipeShrnDtlByShrnId(shareId);
        log.debug("레시피 공유 대상 삭제 완료 - shareId: {}", shareId);

        // 2. 그 다음 부모 테이블(recipe_shrn)의 레코드 삭제
        recipeShrnMapper.deleteRecipeShrn(shareId);

        log.info("레시피 공유 요청 삭제 완료 - recipeId: {}, shareId: {}, userId: {}",
                recipeId, shareId, loginUser.getUserId());
    }

    /**
     * 레시피별 공유 요청 삭제 (레시피 삭제 시)
     */
    @Override
    @Transactional
    public void deleteRecipeShrnByRecipeId(Integer recipeId) throws Exception {
        log.debug("레시피별 공유 요청 삭제 - recipeId: {}", recipeId);

        if (recipeId == null) {
            throw new IllegalArgumentException("레시피 ID는 필수입니다");
        }

        // 1. 먼저 자식 테이블(recipe_shrn_dtl)의 레코드 삭제
        recipeShrnDtlMapper.deleteRecipeShrnDtlByRecipeId(recipeId);
        log.debug("레시피 공유 대상 삭제 완료 - recipeId: {}", recipeId);

        // 2. 그 다음 부모 테이블(recipe_shrn)의 레코드 삭제
        recipeShrnMapper.deleteRecipeShrnByRecipeId(recipeId);

        log.debug("레시피별 공유 요청 삭제 완료 - recipeId: {}", recipeId);
    }

    /**
     * 레시피 공유 요청 중복 확인
     */
    @Override
    public boolean checkRecipeShrnExists(Integer recipeId) throws Exception {
        log.debug("레시피 공유 요청 중복 확인 - recipeId: {}", recipeId);

        if (recipeId == null) {
            throw new IllegalArgumentException("레시피 ID는 필수입니다");
        }

        RecipeShrnVO checkVO = new RecipeShrnVO();
        checkVO.setRecipeId(recipeId);

        int count = recipeShrnMapper.checkRecipeShrnExists(checkVO);
        boolean exists = count > 0;

        log.debug("레시피 공유 요청 중복 확인 완료 - 결과: {}", exists);
        return exists;
    }

    // ========================================
    // 공유 대상 관련 메서드 구현
    // ========================================

    /**
     * 공유 ID별 공유 대상 목록 조회
     */
    @Override
    public List<RecipeShrnDtlVO> getRecipeShrnDtlListByShrnId(Integer shrnId) throws Exception {
        log.debug("공유 ID별 공유 대상 목록 조회 - shrnId: {}", shrnId);

        if (shrnId == null) {
            throw new IllegalArgumentException("공유 ID는 필수입니다");
        }

        List<RecipeShrnDtlVO> list = recipeShrnDtlMapper.selectRecipeShrnDtlListByShrnId(shrnId);
        log.debug("공유 ID별 공유 대상 목록 조회 완료 - 총 {}건", list.size());

        return list;
    }

    /**
     * 레시피 ID별 공유 대상 목록 조회
     */
    @Override
    public List<RecipeShrnDtlVO> getRecipeShrnDtlListByRecipeId(Integer recipeId) throws Exception {
        log.debug("레시피 ID별 공유 대상 목록 조회 - recipeId: {}", recipeId);

        if (recipeId == null) {
            throw new IllegalArgumentException("레시피 ID는 필수입니다");
        }

        List<RecipeShrnDtlVO> list = recipeShrnDtlMapper.selectRecipeShrnDtlListByRecipeId(recipeId);
        log.debug("레시피 ID별 공유 대상 목록 조회 완료 - 총 {}건", list.size());

        return list;
    }

    /**
     * 레시피 공유 대상 추가
     */
    @Override
    @Transactional
    public void addRecipeShrnDtl(RecipeShrnDtlVO recipeShrnDtlVO) throws Exception {
        log.debug("레시피 공유 대상 추가 - shrnId: {}, shrnTrgtCd: {}, shrnTrgtId: {}",
                recipeShrnDtlVO.getShrnId(), recipeShrnDtlVO.getShrnTrgtCd(), recipeShrnDtlVO.getShrnTrgtId());

        // 중복 확인
        int existingCount = recipeShrnDtlMapper.checkRecipeShrnDtlExists(recipeShrnDtlVO);
        if (existingCount > 0) {
            throw new IllegalArgumentException("이미 등록된 공유 대상입니다");
        }

        // 등록
        recipeShrnDtlMapper.insertRecipeShrnDtl(recipeShrnDtlVO);

        log.debug("레시피 공유 대상 추가 완료");
    }

    /**
     * 레시피 공유 대상 일괄 추가
     */
    @Override
    @Transactional
    public void addRecipeShrnDtlList(List<RecipeShrnDtlVO> recipeShrnDtlList) throws Exception {
        log.debug("레시피 공유 대상 일괄 추가 - 총 {}건", recipeShrnDtlList.size());

        if (recipeShrnDtlList == null || recipeShrnDtlList.isEmpty()) {
            throw new IllegalArgumentException("공유 대상 목록이 비어있습니다");
        }

        // 중복 확인 후 필터링
        for (RecipeShrnDtlVO dtl : recipeShrnDtlList) {
            int existingCount = recipeShrnDtlMapper.checkRecipeShrnDtlExists(dtl);
            if (existingCount > 0) {
                log.warn("이미 등록된 공유 대상 건너뜀 - shrnId: {}, shrnTrgtCd: {}, shrnTrgtId: {}",
                        dtl.getShrnId(), dtl.getShrnTrgtCd(), dtl.getShrnTrgtId());
                continue;
            }
        }

        // 일괄 등록
        if (!recipeShrnDtlList.isEmpty()) {
            recipeShrnDtlMapper.insertRecipeShrnDtlList(recipeShrnDtlList);
        }

        log.debug("레시피 공유 대상 일괄 추가 완료");
    }

    /**
     * 레시피 공유 대상 삭제
     */
    @Override
    @Transactional
    public void deleteRecipeShrnDtl(Integer shrnId, String shrnTrgtCd, String shrnTrgtId) throws Exception {
        log.debug("레시피 공유 대상 삭제 - shrnId: {}, shrnTrgtCd: {}, shrnTrgtId: {}", shrnId, shrnTrgtCd, shrnTrgtId);

        if (shrnId == null) {
            throw new IllegalArgumentException("공유 ID는 필수입니다");
        }

        if (shrnTrgtCd == null || shrnTrgtCd.isEmpty()) {
            throw new IllegalArgumentException("공유 대상 코드는 필수입니다");
        }

        if (shrnTrgtId == null || shrnTrgtId.isEmpty()) {
            throw new IllegalArgumentException("공유 대상 ID는 필수입니다");
        }

        recipeShrnDtlMapper.deleteRecipeShrnDtl(shrnId, shrnTrgtCd, shrnTrgtId);

        log.debug("레시피 공유 대상 삭제 완료");
    }

    /**
     * 공유 ID별 공유 대상 전체 삭제
     */
    @Override
    @Transactional
    public void deleteRecipeShrnDtlByShrnId(Integer shrnId) throws Exception {
        log.debug("공유 ID별 공유 대상 전체 삭제 - shrnId: {}", shrnId);

        if (shrnId == null) {
            throw new IllegalArgumentException("공유 ID는 필수입니다");
        }

        recipeShrnDtlMapper.deleteRecipeShrnDtlByShrnId(shrnId);

        log.debug("공유 ID별 공유 대상 전체 삭제 완료");
    }

    /**
     * 레시피 공유 신청 생성 (DTO 기반)
     */
    @Override
    @Transactional
    @OwnerCheck(allowShared = false, message = "레시피 공유 신청 권한이 없습니다")
    public Integer createShareRequest(Integer recipeId, List<ShareTargetDTO> shareTargets, LoginVO loginUser)
            throws Exception {
        log.debug("레시피 공유 신청 생성 - recipeId: {}, userId: {}", recipeId, loginUser.getUserId());

        // 공유 요청 등록
        RecipeShrnVO tempVO = RecipeShrnVO.builder()
                .recipeId(recipeId)
                .aprvStts("P")
                .shrnDmndYmd(java.time.LocalDateTime.now())
                .wrtrId(loginUser.getUserId())
                .frstRegId(loginUser.getUserId())
                .lastMdfcnId(loginUser.getUserId())
                .build();
        recipeShrnMapper.insertRecipeShrn(tempVO);
        Integer shrnId = tempVO.getShrnId();

        // 공유 대상 목록 등록
        if (shareTargets != null && !shareTargets.isEmpty()) {
            List<RecipeShrnDtlVO> dtlList = new ArrayList<>();

            for (ShareTargetDTO target : shareTargets) {
                RecipeShrnDtlVO dtlVO = RecipeShrnDtlVO.builder()
                        .shrnId(shrnId)
                        .recipeId(recipeId)
                        .shrnTrgtCd("N") // 기본값: 미승인(Not Approved)
                        .shrnTrgtId(target.getId()) // userId
                        .frstRegId(loginUser.getUserId())
                        .lastMdfcnId(loginUser.getUserId())
                        .build();

                dtlList.add(dtlVO);

                log.debug("공유 대상 추가 - id: {}", target.getId());
            }

            this.addRecipeShrnDtlList(dtlList);
        }

        log.info("레시피 공유 신청 생성 완료 - shrnId: {}, recipeId: {}, userId: {}, 공유 대상 수: {}",
                shrnId, recipeId, loginUser.getUserId(), shareTargets.size());

        return shrnId;
    }

    /**
     * 레시피 공유 신청 처리 현황 조회
     */
    @Override
    @Transactional(readOnly = true)
    @OwnerCheck(allowShared = false, message = "레시피 공유 현황 조회 권한이 없습니다")
    public List<RecipeShareDTO> getShareStatusList(Integer recipeId, LoginVO loginUser) throws Exception {
        log.debug("레시피 공유 신청 처리 현황 조회 - recipeId: {}", recipeId);

        // recipe_shrn 테이블에서 해당 레시피의 공유 목록 조회
        RecipeShrnVO searchVO = new RecipeShrnVO();
        searchVO.setRecipeId(recipeId);
        searchVO.setPageIndex(1);
        searchVO.setRecordCountPerPage(100);
        searchVO.setFirstIndex(0); // OFFSET 0으로 설정 (첫 페이지부터 조회)

        Map<String, Object> result = this.getRecipeShrnList(searchVO);
        @SuppressWarnings("unchecked")
        List<RecipeShrnVO> shrnList = (List<RecipeShrnVO>) result.get("list");

        // 레시피 레이어 이름 목록 조회 (D: task_lyr, M: user_lyr)
        List<String> layerNames = recipeLayerMapper.selectTaskLayerNamesByRecipeId(recipeId);
        String usedData = layerNames.isEmpty() ? null : String.join(", ", layerNames);

        // DTO 변환
        List<RecipeShareDTO> shareList = new ArrayList<>();

        for (RecipeShrnVO shrn : shrnList) {
            // recipe_shrn_dtl 테이블에서 공유 대상 목록 조회
            List<RecipeShrnDtlVO> dtlList = this.getRecipeShrnDtlListByShrnId(shrn.getShrnId());

            // 공유 대상 이름 목록 (부서-이름 형식)
            List<String> shareTargetNames = new ArrayList<>();

            for (RecipeShrnDtlVO dtl : dtlList) {
                String name = dtl.getShrnTrgtNm();
                String deptNm = dtl.getShrnTrgtDeptNm();
                String displayName;
                if (name != null && !name.isEmpty()) {
                    displayName = (deptNm != null && !deptNm.isEmpty()) ? deptNm + "-" + name : name;
                } else {
                    displayName = dtl.getShrnTrgtId();
                }
                if (displayName != null) {
                    shareTargetNames.add(displayName);
                }
            }

            RecipeShareDTO shareDTO = RecipeShareDTO.builder()
                    .shareId(shrn.getShrnId())
                    .recipeId(shrn.getRecipeId())
                    .recipeNm(shrn.getRecipeNm())
                    .shareTargetNames(shareTargetNames)
                    .usedData(usedData)
                    .shareDate(shrn.getShrnDmndYmd() != null ? shrn.getShrnDmndYmd().toLocalDate().toString() : "")
                    .requesterId(shrn.getWrtrId())
                    .requesterName(shrn.getWrtrNm())
                    .approvalStatus(shrn.getAprvStts())
                    .build();

            shareList.add(shareDTO);
        }

        log.debug("레시피 공유 신청 처리 현황 조회 완료 - recipeId: {}, 조회 건수: {}", recipeId, shareList.size());

        return shareList;
    }

    /**
     * 레시피 공유 상세 정보 조회 (DTO 기반)
     */
    @Override
    @Transactional(readOnly = true)
    public RecipeShareDTO getShareDetail(Integer shareId) throws Exception {
        log.debug("레시피 공유 상세 정보 조회 - shareId: {}", shareId);

        // 공유 정보 조회
        RecipeShrnVO shrn = this.getRecipeShrnDetail(shareId);

        // 공유 대상 목록 조회
        List<RecipeShrnDtlVO> dtlList = this.getRecipeShrnDtlListByShrnId(shareId);

        // 공유 대상 이름 목록 (부서-이름 형식)
        List<String> shareTargetNames = new ArrayList<>();

        for (RecipeShrnDtlVO dtl : dtlList) {
            String name = dtl.getShrnTrgtNm();
            String deptNm = dtl.getShrnTrgtDeptNm();
            String displayName;
            if (name != null && !name.isEmpty()) {
                displayName = (deptNm != null && !deptNm.isEmpty()) ? deptNm + "-" + name : name;
            } else {
                displayName = dtl.getShrnTrgtId();
            }
            if (displayName != null) {
                shareTargetNames.add(displayName);
            }
        }

        // 레시피 레이어 이름 목록 조회 (D: task_lyr, M: user_lyr)
        String usedData = null;
        List<String> layerNames = recipeLayerMapper.selectTaskLayerNamesByRecipeId(shrn.getRecipeId());
        if (layerNames != null && !layerNames.isEmpty()) {
            usedData = String.join(", ", layerNames);
        }

        // DTO 변환
        RecipeShareDTO shareDetail = RecipeShareDTO.builder()
                .shareId(shrn.getShrnId())
                .recipeId(shrn.getRecipeId())
                .recipeNm(shrn.getRecipeNm())
                .shareTargetNames(shareTargetNames)
                .usedData(usedData)
                .shareDate(shrn.getShrnDmndYmd() != null ? shrn.getShrnDmndYmd().toLocalDate().toString() : "")
                .requesterId(shrn.getWrtrId())
                .requesterName(shrn.getWrtrNm())
                .approvalStatus(shrn.getAprvStts())
                .build();

        log.debug("레시피 공유 상세 정보 조회 완료 - shareId: {}", shareId);

        return shareDetail;
    }

    /**
     * 공유받은 레시피 목록 조회 (페이징 포함)
     */
    @Override
    @Transactional(readOnly = true)
    public Map<String, Object> getSharedRecipes(String userId, String searchCondition, String searchKeyword,
            String recipeClsfCd, Integer pageIndex, Integer recordCountPerPage) throws Exception {
        log.debug("공유받은 레시피 목록 조회 - userId: {}, searchCondition: {}, searchKeyword: {}, recipeClsfCd: {}", userId,
                searchCondition, searchKeyword, recipeClsfCd);

        // 검색 조건 설정
        RecipeVO searchVO = new RecipeVO();
        searchVO.setWrtrId(userId);
        searchVO.setSearchCondition(searchCondition);
        searchVO.setSearchKeyword(searchKeyword);
        searchVO.setRecipeClsfCd(recipeClsfCd);
        searchVO.setPageIndex(pageIndex != null ? pageIndex : 1);
        searchVO.setRecordCountPerPage(recordCountPerPage != null ? recordCountPerPage : 10);
        searchVO.setFirstIndex((searchVO.getPageIndex() - 1) * searchVO.getRecordCountPerPage());

        // 공유받은 레시피 목록 조회 (승인된 것만)
        List<RecipeVO> sharedRecipeList = recipeMapper.selectSharedRecipesByUserId(searchVO);

        if (sharedRecipeList.isEmpty()) {
            log.debug("공유받은 레시피 없음 - userId: {}", userId);
            Map<String, Object> result = new HashMap<>();
            result.put("list", new ArrayList<>());
            result.put("totalCount", 0);
            result.put("pageIndex", searchVO.getPageIndex());
            result.put("recordCountPerPage", searchVO.getRecordCountPerPage());
            result.put("totalPages", 0);
            return result;
        }

        // 총 건수 추출 (첫 번째 레코드에서)
        int totalCount = sharedRecipeList.get(0).getTotalCount();
        int totalPages = (int) Math.ceil((double) totalCount / searchVO.getRecordCountPerPage());

        List<RecipeDetailDTO> sharedRecipes = new ArrayList<>();
        for (RecipeVO recipe : sharedRecipeList) {
            // 공유수 조회 (승인 완료된 공유 대상자 수)
            int shareCount = 0;
            shareCount = recipeShrnMapper.selectRecipeShareCount(recipe.getRecipeId());

            RecipeDetailDTO recipeDetail = RecipeDetailDTO.builder()
                    .recipeId(recipe.getRecipeId())
                    .wrtrId(recipe.getWrtrId())
                    .wrtrNm(recipe.getWrtrNm())
                    .recipeNm(recipe.getRecipeNm())
                    .recipeExpln(recipe.getRecipeExpln())
                    .recipeCchInfo(recipe.getRecipeCchInfoJson())
                    .thmbUrl(recipe.getThmbUrl())
                    .dgmPeinInfo(recipe.getDgmPeinInfoJson())
                    .recipeClsfCd(recipe.getRecipeClsfCd())
                    .inqCnt(recipe.getInqCnt())
                    .shareCount(shareCount)
                    .lastPrslHr(recipe.getLastPrslHr())
                    .frstRegDt(recipe.getFrstRegDt())
                    .frstRegId(recipe.getFrstRegId())
                    .lastMdfcnDt(recipe.getLastMdfcnDt())
                    .lastMdfcnId(recipe.getLastMdfcnId())
                    .recipeLayerList(null)
                    .isImported(false)
                    .build();
            sharedRecipes.add(recipeDetail);
        }

        log.debug("공유받은 레시피 목록 조회 완료 - userId: {}, 총 건수: {}, 조회 건수: {}",
                userId, totalCount, sharedRecipes.size());

        // 결과 반환
        Map<String, Object> result = new HashMap<>();
        result.put("list", sharedRecipes);
        result.put("totalCount", totalCount);
        result.put("pageIndex", searchVO.getPageIndex());
        result.put("recordCountPerPage", searchVO.getRecordCountPerPage());
        result.put("totalPages", totalPages);

        return result;
    }

    /**
     * 관리자용 공유 승인 대기 목록 조회
     */
    @Override
    @Transactional(readOnly = true)
    public Map<String, Object> getApprovalRequests(String searchCondition, String searchKeyword, String recipeClsfCd,
            Integer pageIndex, Integer recordCountPerPage, String requestUserId) throws Exception {
        log.debug("관리자용 공유 승인 대기 목록 조회 - recipeClsfCd: {}, requestUserId: {}", recipeClsfCd, requestUserId);

        // 검색 조건 설정 (승인 대기 상태만)
        RecipeShrnVO searchVO = new RecipeShrnVO();
        searchVO.setAprvStts("P"); // 대기 상태만
        searchVO.setSearchKeyword(searchKeyword);
        searchVO.setSearchCondition(searchCondition);
        searchVO.setRecipeClsfCd(recipeClsfCd);
        searchVO.setPageIndex(pageIndex);
        searchVO.setRecordCountPerPage(recordCountPerPage);

        // firstIndex 계산 (OFFSET 계산용)
        int firstIndex = (pageIndex - 1) * recordCountPerPage;
        searchVO.setFirstIndex(firstIndex);

        // 승인 대기 목록 조회
        Map<String, Object> result = this.getRecipeShrnList(searchVO);
        @SuppressWarnings("unchecked")
        List<RecipeShrnVO> shrnList = (List<RecipeShrnVO>) result.get("list");

        // DTO 변환
        List<RecipeShareDTO> approvalList = new ArrayList<>();
        for (RecipeShrnVO shrn : shrnList) {
            // 공유 대상 목록 조회
            List<RecipeShrnDtlVO> dtlList = this.getRecipeShrnDtlListByShrnId(shrn.getShrnId());

            // 공유 대상 이름 목록 (부서-이름 형식)
            List<String> shareTargetNames = new ArrayList<>();

            for (RecipeShrnDtlVO dtl : dtlList) {
                String name = dtl.getShrnTrgtNm();
                String deptNm = dtl.getShrnTrgtDeptNm();
                String displayName;
                if (name != null && !name.isEmpty()) {
                    displayName = (deptNm != null && !deptNm.isEmpty()) ? deptNm + "-" + name : name;
                } else {
                    displayName = dtl.getShrnTrgtId();
                }
                if (displayName != null) {
                    shareTargetNames.add(displayName);
                }
            }

            // 레시피 레이어 이름 목록 조회하여 사용 데이터 추출 (D: task_lyr, M: user_lyr)
            String usedData = null;
            List<String> layerNames = recipeLayerMapper.selectTaskLayerNamesByRecipeId(shrn.getRecipeId());
            if (!layerNames.isEmpty()) {
                usedData = String.join(", ", layerNames);
            }

            RecipeShareDTO shareDTO = RecipeShareDTO.builder()
                    .shareId(shrn.getShrnId())
                    .recipeId(shrn.getRecipeId())
                    .recipeNm(shrn.getRecipeNm())
                    .thmbUrl(shrn.getThmbUrl())
                    .shareTargetNames(shareTargetNames)
                    .usedData(usedData)
                    .shareDate(shrn.getShrnDmndYmd() != null ? shrn.getShrnDmndYmd().toLocalDate().toString() : "")
                    .requesterId(shrn.getWrtrId())
                    .requesterName(shrn.getWrtrNm())
                    .approvalStatus(shrn.getAprvStts())
                    .build();

            approvalList.add(shareDTO);
        }

        log.debug("관리자용 공유 승인 대기 목록 조회 완료 - 조회 건수: {}", approvalList.size());
        // 기존 페이징 정보는 유지하고 list만 DTO로 교체
        result.put("list", approvalList);
        return result;
    }

    /**
     * 공유 승인 처리 (검증 포함)
     */
    @Override
    @Transactional
    public void approveShare(Integer shareId, String requestUserId) throws Exception {
        log.debug("공유 승인 처리 - shareId: {}, 승인자: {}", shareId, requestUserId);

        // 공유 요청 존재 확인
        RecipeShrnVO shrn = this.getRecipeShrnDetail(shareId);
        if (shrn == null) {
            throw new IllegalArgumentException("공유 요청을 찾을 수 없습니다.");
        }

        // 이미 처리된 요청인지 확인
        if (!"P".equals(shrn.getAprvStts())) {
            throw new IllegalArgumentException("이미 처리된 공유 요청입니다.");
        }

        // 공유 승인 처리 - 승인 상태 및 승인 날짜 업데이트
        RecipeShrnVO updateVO = new RecipeShrnVO();
        updateVO.setShrnId(shareId);
        updateVO.setAprvStts("Y");
        updateVO.setShrnAprvYmd(java.time.LocalDateTime.now());
        updateVO.setLastMdfcnId(requestUserId);

        recipeShrnMapper.updateRecipeShrnStatus(updateVO);

        log.debug("공유 승인 처리 완료 - shareId: {}, 승인 일시: {}", shareId, updateVO.getShrnAprvYmd());
    }

    /**
     * 공유 거부 처리 (검증 포함)
     */
    @Override
    @Transactional
    public void rejectShare(Integer shareId, String requestUserId) throws Exception {
        log.debug("공유 거부 처리 - shareId: {}, 거부자: {}", shareId, requestUserId);

        // 공유 요청 존재 확인
        RecipeShrnVO shrn = this.getRecipeShrnDetail(shareId);
        if (shrn == null) {
            throw new IllegalArgumentException("공유 요청을 찾을 수 없습니다.");
        }

        // 이미 처리된 요청인지 확인
        if (!"P".equals(shrn.getAprvStts())) {
            throw new IllegalArgumentException("이미 처리된 공유 요청입니다.");
        }

        // 공유 거부 처리 - 거부 상태 및 거부 날짜 업데이트
        RecipeShrnVO updateVO = new RecipeShrnVO();
        updateVO.setShrnId(shareId);
        updateVO.setAprvStts("N");
        updateVO.setShrnAprvYmd(java.time.LocalDateTime.now());
        updateVO.setLastMdfcnId(requestUserId);

        recipeShrnMapper.updateRecipeShrnStatus(updateVO);

        log.debug("공유 거부 처리 완료 - shareId: {}, 거부 일시: {}", shareId, updateVO.getShrnAprvYmd());
    }
}
