package com.madeu.crm.settings.medicalcategory.service;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.madeu.constants.Constants;
import com.madeu.crm.settings.medicalcategory.dto.MedicalCategoryDTO;
import com.madeu.crm.settings.medicalcategory.mapper.MedicalCategoryMapper;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class MedicalCategoryService {

    @Autowired
    private MedicalCategoryMapper medicalCategoryMapper;

    /**
     * 카테고리 트리 리스트 조회
     */
    public HashMap<String, Object> getMedicalCategoryTreeList(HashMap<String, Object> paramMap) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        List<Map<String, Object>> resultList = new ArrayList<>();

        try {
            // DB에서 전체 목록 조회 (list_use='y') - 정렬순은 divi_dept, divi_sort 기준
            List<Map<String, Object>> listMap = medicalCategoryMapper.getMedicalCategoryList(paramMap);

            if (listMap != null && !listMap.isEmpty()) {
                // Tabulator 의 dataTree 모드를 사용하기 위해, 평면 구조(Flat)를 받아서 프론트엔드가 자체적으로 Tree로 엮거나
                // 직접 백엔드에서 `_children` 프로퍼티를 만들어서 계층형으로 보내주는 두 가지 방식이 있습니다.
                // 여기서는 Tabulator 가 dataTreeChildField: "_children" 속성으로 자동 파싱하기 쉽도록
                // 백엔드에서 부모-자식 트리 구조로 조립해서 보냅니다.

                resultList = buildTree(listMap);
            }

            map.put("msgCode", Constants.OK);
            map.put("success", true);
            map.put("rows", resultList);

        } catch (Exception e) {
            log.error("getMedicalCategoryTreeList Error: ", e);
            throw e;
        }

        return map;
    }

    /**
     * 평면형(Flat) List를 Tabulator Tree(계층형) 구조로 변환하는 헬퍼 메서드
     */
    private List<Map<String, Object>> buildTree(List<Map<String, Object>> flatList) {
        // pid를 키로 하는 Map 구조 생성 (빠른 접근 위함)
        Map<Integer, Map<String, Object>> nodeMap = new HashMap<>();
        List<Map<String, Object>> roots = new ArrayList<>();

        for (Map<String, Object> flatNode : flatList) {
            // 자식 목록을 담을 공간 초기화
            flatNode.put("_children", new ArrayList<Map<String, Object>>());
            // pid
            Integer pid = Integer.parseInt(String.valueOf(flatNode.get("pid")));
            nodeMap.put(pid, flatNode);
        }

        for (Map<String, Object> flatNode : flatList) {
            Integer diviParent = Integer.parseInt(String.valueOf(flatNode.get("divi_parent")));

            if (diviParent == 0) {
                // 부모가 0이면 최상위(Depth 1) 노드
                roots.add(flatNode);
            } else {
                // 부모가 있으면 부모 노드를 찾아서 _children 리스트에 추가
                Map<String, Object> parentNode = nodeMap.get(diviParent);
                if (parentNode != null) {
                    @SuppressWarnings("unchecked")
                    List<Map<String, Object>> children = (List<Map<String, Object>>) parentNode.get("_children");
                    children.add(flatNode);
                } else {
                    // 고아 노드일 경우 (부모가 삭제되었거나 매칭오류) 어떻게 처리할지 정책
                    // roots.add(flatNode);
                }
            }
        }
        return roots;
    }

    /**
     * 카테고리 정보 부분 다건 일괄 수정 (전체보기 저장)
     * 
     * @param list
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> updateBatchMedicalCategory(List<MedicalCategoryDTO> list) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        try {
            int successCount = 0;
            for (MedicalCategoryDTO dto : list) {
                // dto의 빈 값은 쿼리의 <if> 조건을 통과하지 않아 업데이트 되지 않음
                successCount += medicalCategoryMapper.updateMedicalCategory(dto);
            }
            if (successCount > 0) {
                map.put("msgCode", Constants.OK);
                map.put("success", true);
                map.put("msgDesc", successCount + "건이 수정되었습니다.");
            } else {
                map.put("msgCode", Constants.FAIL);
                map.put("msgDesc", "수정 사항이 없거나 실패했습니다.");
            }
        } catch (Exception e) {
            log.error("updateBatchMedicalCategory Error: ", e);
            throw e;
        }
        return map;
    }

    /**
     * 특정 카테고리 상세 정보 조회
     */
    public HashMap<String, Object> getMedicalCategory(HashMap<String, Object> paramMap) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        try {
            Map<String, Object> categoryMap = medicalCategoryMapper.getMedicalCategory(paramMap);
            map.put("msgCode", Constants.OK);
            map.put("success", true);
            map.put("data", categoryMap);
        } catch (Exception e) {
            log.error("getMedicalCategory Error: ", e);
            throw e;
        }
        return map;
    }

    /**
     * 거래처 목록 조회
     */
    public HashMap<String, Object> getCustList(HashMap<String, Object> paramMap) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        try {
            List<Map<String, Object>> list = medicalCategoryMapper.getCustList(paramMap);
            map.put("msgCode", Constants.OK);
            map.put("success", true);
            map.put("data", list);
        } catch (Exception e) {
            log.error("getCustList Error: ", e);
            throw e;
        }
        return map;
    }

    /**
     * 카테고리 등록
     * 
     * @param dto
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> insertMedicalCategory(MedicalCategoryDTO dto) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        try {
            int result = medicalCategoryMapper.insertMedicalCategory(dto);
            if (result > 0) {
                map.put("msgCode", Constants.OK);
                map.put("success", true);
                map.put("msgDesc", "등록되었습니다.");
            } else {
                map.put("msgCode", Constants.FAIL);
                map.put("msgDesc", "등록에 실패했습니다.");
            }
        } catch (Exception e) {
            log.error("insertMedicalCategory Error: ", e);
            throw e;
        }
        return map;
    }

    /**
     * 카테고리 수정
     * 
     * @param dto
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> updateMedicalCategory(MedicalCategoryDTO dto) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        try {
            int result = medicalCategoryMapper.updateMedicalCategory(dto);
            if (result > 0) {
                map.put("msgCode", Constants.OK);
                map.put("success", true);
                map.put("msgDesc", "수정되었습니다.");
            } else {
                map.put("msgCode", Constants.FAIL);
                map.put("msgDesc", "존재하지 않는 데이터이거나 수정 실패했습니다.");
            }
        } catch (Exception e) {
            log.error("updateMedicalCategory Error: ", e);
            throw e;
        }
        return map;
    }

    /**
     * 카테고리 삭제 (논리 삭제 처리)
     * 
     * @param paramMap
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> deleteMedicalCategory(HashMap<String, Object> paramMap) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        try {
            // 1. 하위 카테고리가 존재하는지 여부 확인
            int childCount = medicalCategoryMapper.getChildCategoryCount(paramMap);
            if (childCount > 0) {
                map.put("msgCode", Constants.FAIL);
                map.put("msgDesc", "하위 항목이 존재하여 삭제할 수 없습니다. 먼저 하위 항목을 삭제하세요.");
                return map;
            }

            // 2. 삭제 처리
            int result = medicalCategoryMapper.deleteMedicalCategory(paramMap);
            if (result > 0) {
                map.put("msgCode", Constants.OK);
                map.put("success", true);
                map.put("msgDesc", "삭제되었습니다.");
            } else {
                map.put("msgCode", Constants.FAIL);
                map.put("msgDesc", "삭제 실패했습니다.");
            }
        } catch (Exception e) {
            log.error("deleteMedicalCategory Error: ", e);
            throw e;
        }
        return map;
    }

    /**
     * 카테고리 다건 삭제 (논리 삭제 처리)
     * 하위 항목이 있는 카테고리는 건너뛰고, 나머지만 삭제 처리
     * 
     * @param pidList 삭제 대상 pid 목록
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> deleteMultiMedicalCategory(List<String> pidList) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        int successCount = 0;
        int skipCount = 0;
        List<String> skippedNames = new ArrayList<>();

        try {
            for (String pidStr : pidList) {
                HashMap<String, Object> paramMap = new HashMap<>();
                paramMap.put("pid", pidStr);

                // 하위 카테고리 존재 여부 확인
                int childCount = medicalCategoryMapper.getChildCategoryCount(paramMap);
                if (childCount > 0) {
                    // 하위 항목이 있으면 건너뜀
                    Map<String, Object> info = medicalCategoryMapper.getMedicalCategory(paramMap);
                    if (info != null && info.get("divi_name") != null) {
                        skippedNames.add(String.valueOf(info.get("divi_name")));
                    }
                    skipCount++;
                    continue;
                }

                // 삭제 처리
                int result = medicalCategoryMapper.deleteMedicalCategory(paramMap);
                if (result > 0) {
                    successCount++;
                }
            }

            if (successCount > 0) {
                map.put("msgCode", Constants.OK);
                map.put("success", true);
            } else {
                map.put("msgCode", Constants.FAIL);
            }

            // 결과 메시지 구성
            StringBuilder msg = new StringBuilder();
            if (successCount > 0) {
                msg.append(successCount + "건 삭제되었습니다.");
            }
            if (skipCount > 0) {
                if (msg.length() > 0)
                    msg.append("\n");
                msg.append(skipCount + "건은 하위 항목이 존재하여 건너뛰었습니다.");
                if (!skippedNames.isEmpty()) {
                    msg.append("\n(" + String.join(", ", skippedNames) + ")");
                }
            }
            if (successCount == 0 && skipCount == 0) {
                msg.append("삭제할 항목이 없습니다.");
            }
            map.put("msgDesc", msg.toString());

        } catch (Exception e) {
            log.error("deleteMultiMedicalCategory Error: ", e);
            throw e;
        }
        return map;
    }

    /**
     * 카테고리 정보 부분 수정 (인라인 에디팅)
     * 
     * @param paramMap
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> updatePartialMedicalCategory(HashMap<String, Object> paramMap) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        try {
            int result = medicalCategoryMapper.updatePartialMedicalCategory(paramMap);
            if (result > 0) {
                map.put("msgCode", Constants.OK);
                map.put("success", true);
                map.put("msgDesc", "수정되었습니다.");
            } else {
                map.put("msgCode", Constants.FAIL);
                map.put("msgDesc", "수정 실패했습니다.");
            }
        } catch (Exception e) {
            log.error("updatePartialMedicalCategory Error: ", e);
            throw e;
        }
        return map;
    }

}
