package com.icomsys.main_vm.biz.rcp.conversation.service;

import com.google.gson.Gson;
import com.icomsys.main_vm.biz.advice.excep.CustomBadRequestException;
import com.icomsys.main_vm.biz.advice.excep.CustomNotFoundException;
import com.icomsys.main_vm.biz.common.common.service.LogService;
import com.icomsys.main_vm.biz.common.common.service.LogVO;
import com.icomsys.main_vm.biz.common.login.service.LoginService;
import com.icomsys.main_vm.biz.common.system.vo.DslDataTableRes;
import com.icomsys.main_vm.biz.rcp.conversation.vo.*;
import com.icomsys.main_vm.biz.rcp.util.ScenarioConverter;
import com.icomsys.main_vm.common.code.code.LongTextManagerColumnCode;
import com.icomsys.main_vm.common.code.code.LongTextManagerTableCode;
import com.icomsys.main_vm.common.code.enumresource.ActionResource;
import com.icomsys.main_vm.common.code.enumresource.MenuResource;
import com.icomsys.main_vm.db.jpa.entity.scenario.TbCommonNode;
import com.icomsys.main_vm.db.jpa.entity.scenario.TbLongtextManager;
import com.icomsys.main_vm.db.jpa.entity.scenario.id.TbLongtextManagerId;
import com.icomsys.main_vm.db.jpa.entity.system.TbServiceGrouop;
import com.icomsys.main_vm.db.jpa.repo.scenario.TbCommonNodeRepo;
import com.icomsys.main_vm.db.jpa.repo.scenario.TbLongtextManagerRepo;
import com.icomsys.main_vm.db.jpa.repo.system.TbServiceGrouopRepo;
import com.querydsl.core.QueryResults;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;

/**
 * Name : ConversationCmmNodeService 
 * date : 2023-02-13 
 * author :  Mong
 * description :
 * ===========================================================
 * DATE                 AUTHOR                NOTE
 * -----------------------------------------------------------
 * 2023-02-13                Mong             최초 생성
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ConversationCmmNodeService {

    private final TbCommonNodeRepo tbCommonNodeRepo;
    private final TbLongtextManagerRepo tbLongtextManagerRepo;
    private final TbServiceGrouopRepo tbServiceGrouopRepo;
    private final LoginService loginService;
    private final LogService logService;

    public DslDataTableRes<ConversationCmmNodeInfoRes> selectCmmNodeList(ConversationCmmNodeInfoReq dto) throws CustomNotFoundException {
        if (dto.isContainUpper()) {     // 상위 그룹포함 검색일 경우
            TbServiceGrouop serviceGrouop = tbServiceGrouopRepo.findByServiceGroup(dto.getServiceGroup())
                    .orElseThrow(() -> new CustomNotFoundException("서비스 그룹 정보가 없습니다."));

            dto.setServiceGroupUpper(serviceGrouop.getServiceGroupUpper());
        }

        QueryResults<ConversationCmmNodeInfoRes> result = tbCommonNodeRepo.serachCmmNodeList(dto);
        return new DslDataTableRes<ConversationCmmNodeInfoRes>(result);
    }

    @Transactional(readOnly = true)
    public ConversationCmmNodeDiagramVO selectCmmNode(ConversationCmmNodeEditReq dto) throws CustomNotFoundException {
        ConversationCmmNodeDiagramVO vo = new ConversationCmmNodeDiagramVO();
        TbLongtextManagerId tlm = new TbLongtextManagerId();
        Long seq = dto.getSeq();

        if (seq == null) { // 시나리오 초기 생성
            return vo;
        }

        tlm.setRfSeq(seq);
        tlm.setTableCode(LongTextManagerTableCode.TB_COMMON_NODE.getCode());
        tlm.setColumnCode(LongTextManagerColumnCode.DIAGRAM.getCode());
        log.info("tlm -> {} ", new Gson().toJson(tlm));

        TbCommonNode result1 = tbCommonNodeRepo.findBySeqAndUseYn(seq, "Y").
                orElseThrow(() -> new CustomNotFoundException("Common Node를 찾지 못하였습니다."));

        TbLongtextManager result = tbLongtextManagerRepo.findById(tlm).
                orElseThrow(() -> new CustomNotFoundException("다이어그램 정보를 찾지 못하였습니다."));

        vo.setSeq(result.getRfSeq());
        vo.setTextContents(result.getTextContents());
        vo.setNodeName(result1.getNodeName());
        vo.setOprMngCode(result1.getOprMngCode());

        return vo;

    }

    @Transactional
    public int saveCmmNode(ConversationCmmNodeEditReq dto) throws CustomBadRequestException {

        String userId = loginService.getUserVo().getUserId();
        LocalDateTime currentDateTime = LocalDateTime.now();
        String oprMngCode = dto.getCustCode() + "_RCP_" +  dto.getServiceGroup();

        ScenarioConverter scenarioConverter = new ScenarioConverter(dto.getTextContents());
        scenarioConverter.convertDiagramToCallScenario();
        try {
            scenarioConverter.createChecksum();
        } catch (NoSuchAlgorithmException e) {
            throw new CustomBadRequestException("Common Node 해시값 생성에 실패하였습니다.");
        }

        TbCommonNode vo = new TbCommonNode();
        vo.setNodeName(dto.getNodeName());
        vo.setUseYn("Y");
        vo.setRegistId(userId);
        vo.setRegistDate(currentDateTime);
        vo.setUpdateId(userId);
        vo.setUpdateDate(currentDateTime);
        vo.setOprMngCode(oprMngCode);

        TbCommonNode result = tbCommonNodeRepo.save(vo);

        // Diagram 저장
        tbLongtextManagerRepo.save(new TbLongtextManager(
                result.getSeq(),
                LongTextManagerTableCode.TB_COMMON_NODE.getCode(),
                LongTextManagerColumnCode.DIAGRAM.getCode(),
                scenarioConverter.getDiagramString(),
                scenarioConverter.getDiagramChecksum()));

        // Call Scenario 저장
        tbLongtextManagerRepo.save(new TbLongtextManager(
                result.getSeq(),
                LongTextManagerTableCode.TB_COMMON_NODE.getCode(),
                LongTextManagerColumnCode.SCENARIO.getCode(),
                scenarioConverter.getCallScenarioString(),
                scenarioConverter.getCallScenarioChecksum()));

        logService.LogSave(LogVO.builder()
                .menuAuth(MenuResource.rcpconversationcmmNodemanage)
                .serviceGroup(dto.getServiceGroup())
                .actionCode(ActionResource.insert.getName())
                .build());

        return Math.toIntExact(result.getSeq());
    }

    @Transactional
    public int updateCmmNode(ConversationCmmNodeEditReq dto) throws CustomBadRequestException, CustomNotFoundException {
        Long seq = dto.getSeq();
        LocalDateTime currentDateTime = LocalDateTime.now();
        String userId = loginService.getUserVo().getUserId();

        if (dto.getNodeName() == null || dto.getNodeName().isEmpty()) {
            throw new CustomBadRequestException("Common Node명을 입력해주세요");
        }

        // diagram checksum 확인
        TbCommonNode commonNode = tbCommonNodeRepo.findBySeqAndUseYn(seq, "Y").
                orElseThrow(() -> new CustomNotFoundException("Common Node를 찾지 못하였습니다."));

        ScenarioConverter scenarioConverter = new ScenarioConverter(dto.getTextContents());
        scenarioConverter.convertDiagramToCallScenario();
        try {
            scenarioConverter.createChecksum();
        } catch (NoSuchAlgorithmException e) {
            throw new CustomBadRequestException("Common Node 해시값 생성에 실패하였습니다.");
        }

        TbLongtextManager diagram = tbLongtextManagerRepo.findById(
                new TbLongtextManagerId(seq,
                        LongTextManagerTableCode.TB_COMMON_NODE.getCode(),
                        LongTextManagerColumnCode.DIAGRAM.getCode()))
                .orElseThrow(() -> new CustomNotFoundException("다이어그램을 찾지 못하였습니다."));

        TbLongtextManager scenario = tbLongtextManagerRepo.findById(
                new TbLongtextManagerId(seq,
                        LongTextManagerTableCode.TB_COMMON_NODE.getCode(),
                        LongTextManagerColumnCode.SCENARIO.getCode()))
                .orElseThrow(() -> new CustomNotFoundException("시나리오를 찾지 못하였습니다."));

        boolean isUpdate = false;
        String nodeName = dto.getNodeName();
        String oprMngCode = dto.getCustCode() + "_RCP_" +  dto.getServiceGroup();

        if (!commonNode.getNodeName().equals(nodeName) || !commonNode.getOprMngCode().equals(oprMngCode)) {
            // 이름, oprMngCode 변경값이 있는 경우 업데이트
            commonNode.setNodeName(nodeName);
            commonNode.setOprMngCode(oprMngCode);
            commonNode.setUpdateId(userId);
            commonNode.setUpdateDate(currentDateTime);
            tbCommonNodeRepo.save(commonNode);
            isUpdate = true;
        }

        if (diagram.getChecksum().equals(scenarioConverter.getDiagramChecksum()) ) { // 다이어그램 변경 값이 없음
            if (!isUpdate) {
                throw new CustomBadRequestException("시나리오 변경 값이 없습니다.");
            }
        } else {
            // 다이어그램, 콜 시나리오 업데이트
            diagram.setChecksum(scenarioConverter.getDiagramChecksum());
            diagram.setTextContents(scenarioConverter.getDiagramString());

            scenario.setChecksum(scenarioConverter.getCallScenarioChecksum());
            scenario.setTextContents(scenarioConverter.getCallScenarioString());

            tbLongtextManagerRepo.save(diagram);
            tbLongtextManagerRepo.save(scenario);

            // 업데이트 날짜 변경
            commonNode.setUpdateId(userId);
            commonNode.setUpdateDate(currentDateTime);
            tbCommonNodeRepo.save(commonNode);
        }

        logService.LogSave(LogVO.builder()
                .menuAuth(MenuResource.rcpconversationcmmNodemanage)
                .serviceGroup(dto.getServiceGroup())
                .actionCode(ActionResource.update.getName())
                .build());

        return 0;
    }

    @Transactional
    public int deleteCmmNode(HashMap map){
        Long seq = Long.parseLong(String.valueOf(map.get("seq")));
        String serviceGroup = String.valueOf(map.get("serviceGroup"));
        log.info("seq -> {} " , seq);
        tbCommonNodeRepo.deleteCmmNode(seq);

        logService.LogSave(LogVO.builder()
                .menuAuth(MenuResource.rcpconversationcmmNodemanage)
                .actionCode(ActionResource.delete.getName())
                .serviceGroup(serviceGroup)
                .build());
        return 0;
    }

}
