package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.strategy;

import cokr.xit.ens.core.exception.EnsException;
import cokr.xit.ens.core.exception.code.EnsErrCd;
import cokr.xit.ens.core.utils.CmmnUtil;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.TmpltMngIntgrn;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngIntgrnRepository;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.struct.TmpltMngIntgrnMapper;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.OrgMngRepository;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepository;
import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO;
import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO;
import cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy.TmpltMngStrategyTemplate;
import cokr.xit.ens.modules.kkoalimtalk.domain.TmpltMngKkoAlimtalk;
import cokr.xit.ens.modules.kkoalimtalk.model.struct.TmpltMngKkoAlimtalkMapper;
import cokr.xit.ens.modules.kkomydoc.domain.TmpltMngKkoMydoc;
import cokr.xit.ens.modules.kkomydoc.model.struct.TmpltMngKkoMydocMapper;
import cokr.xit.ens.modules.nvsigntalk.domain.TmpltMngNvSigntalk;
import cokr.xit.ens.modules.nvsigntalk.model.struct.TmpltMngNvSigntalkMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.RequiredArgsConstructor;
import org.mapstruct.factory.Mappers;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.*;
import java.util.stream.Collectors;

@Component("tmpltMngStrategy_intgrn")
@RequiredArgsConstructor
public class TmpltMngStrategyIntegration extends TmpltMngStrategyTemplate<Map<String, Object>, TmpltMngIntgrnDTO> {

    private final OrgMngRepository orgMngRepository;
    private final TmpltMngRepository tmpltMngRepository;
    private final TmpltMngIntgrnRepository tmpltMngIntgrnRepository;
    private final cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngKkoAlimtalkMapper tmpltMngKkoAlimtalkMapper;
    private final cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngKkoMydocMapper tmpltMngKkoMydocMapper;
    private final cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngNvSigntalkMapper tmpltMngNvSigntalkMapper;
//    private final RedisTemplate redisTemplate;

    private TmpltMngIntgrnMapper intgrnMapper = Mappers.getMapper(TmpltMngIntgrnMapper.class);

    @Override
    public List<TmpltMngIntgrnDTO> findAll(TmpltMngSearchDTO tmpltMngSearchDTO) {
        return tmpltMngIntgrnRepository.findAllDtoBySearchDTO(tmpltMngSearchDTO);
    }

    @Override
    public Optional<TmpltMngIntgrnDTO> find(String orgCd, String tmpltCd) {
        return tmpltMngIntgrnRepository.findDtoByOrgCdAndTmpltCd(orgCd, tmpltCd);

//        String key = super.pushCache(redisTemplate, orgCd, tmpltCd, tmpltMngIntgrnRepository);
//        HashOperations<String, String, TmpltMngIntgrnDTO> hashOperations = redisTemplate.opsForHash();
//        return Optional.ofNullable(hashOperations.entries(KEY).get(key));
    }

    @Override
    protected TmpltMngIntgrnDTO validate(Map<String, Object> params) {
        try {
            if (params.getOrDefault("nvSigntalk", null) != null) {
                Map<String, Object> nvSigntalk = (Map<String, Object>) params.get("nvSigntalk");
                if (nvSigntalk.getOrDefault("messageDataFmt", null) != null)
                    nvSigntalk.put("messageDataFmt", mapper.writeValueAsString(nvSigntalk.get("messageDataFmt")));
            }

            TmpltMngIntgrnDTO dto = mapper.convertValue(params, TmpltMngIntgrnDTO.class);
            if (!CmmnUtil.isEmpty(dto.getKkoAlimtalk()))
                this.toMappedChildTmpltMng(dto, dto.getKkoAlimtalk());
            if (!CmmnUtil.isEmpty(dto.getKkoMydoc()))
                this.toMappedChildTmpltMng(dto, dto.getKkoMydoc());
            if (!CmmnUtil.isEmpty(dto.getNvSigntalk()))
                this.toMappedChildTmpltMng(dto, dto.getNvSigntalk());

            final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
            Set<ConstraintViolation<TmpltMngIntgrnDTO>> list = validator.validate(dto);
            if (list.size() > 0) {
                throw new EnsException(EnsErrCd.ERR410, "유효하지 않은 요청 값 입니다.", list.stream()
                        .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath()))
                        .collect(Collectors.toList())
                );
            }
            return dto;
        } catch (IllegalArgumentException e) {
            List<String> fields = Arrays.stream(TmpltMngDTO.class.getDeclaredFields()).map(row -> row.getName()).collect(Collectors.toList());
            fields.addAll(Arrays.stream(TmpltMngIntgrnDTO.class.getDeclaredFields()).map(row -> row.getName()).collect(Collectors.toList()));
            throw new EnsException(EnsErrCd.ERR403, "유효하지 않은 파라미터 입니다. 사용가능한 파라미터는 resultInfo 를 참고하시기 바랍니다.", fields);
        } catch (JsonProcessingException e) {
            throw new EnsException(EnsErrCd.ERR403, "nvSigntalk.messageDataFmt 변환에 실패했습니다.");
        }

    }

    @Override
    protected void addProc(TmpltMngIntgrnDTO dto) {
        OrgMng orgMng = orgMngRepository.findById(dto.getOrgCd()).orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s)가 일치하는 자료가 없습니다.", dto.getOrgCd())));
        tmpltMngRepository.findFetchByOrgCdAndTmpltCd(dto.getOrgCd(), dto.getTmpltCd())
                .ifPresent(tmpltMng -> {
                    throw new EnsException(EnsErrCd.ERR540, String.format("이미 등록된 템플릿코드[기관코드 %s 템플릿코드 %s] 입니다.", tmpltMng.getOrgMng().getOrgCd(), tmpltMng.getTmpltCd()));
                });

        TmpltMngIntgrn tmpltMng = intgrnMapper.toEntity(dto);
        tmpltMng.setOrgMng(orgMng);
        tmpltMng.setRegistId("ENS_SYS");
        tmpltMngIntgrnRepository.saveAndFlush(tmpltMng);

        if (!CmmnUtil.isEmpty(dto.getKkoAlimtalk())) {
            TmpltMngKkoAlimtalkMapper mapper = Mappers.getMapper(TmpltMngKkoAlimtalkMapper.class);
            TmpltMngKkoAlimtalk tmpltChild = mapper.toEntity(dto.getKkoAlimtalk());
            tmpltMngKkoAlimtalkMapper.add(tmpltChild);
        }
        if (!CmmnUtil.isEmpty(dto.getKkoMydoc())) {
            TmpltMngKkoMydocMapper mapper = Mappers.getMapper(TmpltMngKkoMydocMapper.class);
            TmpltMngKkoMydoc tmpltChild = mapper.toEntity(dto.getKkoMydoc());
            tmpltMngKkoMydocMapper.add(tmpltChild);
        }
        if (!CmmnUtil.isEmpty(dto.getNvSigntalk())) {
            TmpltMngNvSigntalkMapper mapper = Mappers.getMapper(TmpltMngNvSigntalkMapper.class);
            TmpltMngNvSigntalk tmpltChild = mapper.toEntity(dto.getNvSigntalk());
            tmpltMngNvSigntalkMapper.add(tmpltChild);
        }


    }

    @Override
    protected void modifyProc(TmpltMngIntgrnDTO dto) {
        TmpltMngIntgrn tmpltMng = tmpltMngIntgrnRepository.findFetchByOrgCdAndTmpltCd(dto.getOrgCd(), dto.getTmpltCd())
                .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s) 및 템플릿코드(%s)가 일치하는 자료가 없습니다.", dto.getOrgCd(), dto.getTmpltCd())));
        intgrnMapper.updateFromDto(dto, tmpltMng);
        tmpltMng.setUpdId("ENS_SYS");


        if (!CmmnUtil.isEmpty(dto.getKkoAlimtalk())) {
            TmpltMngKkoAlimtalkMapper mapper = Mappers.getMapper(TmpltMngKkoAlimtalkMapper.class);
            TmpltMngKkoAlimtalk tmpltChild = mapper.toEntity(dto.getKkoAlimtalk());
            if (tmpltMngKkoAlimtalkMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) {
                tmpltChild.setUpdId("ENS_SYS");
                tmpltMngKkoAlimtalkMapper.modify(tmpltChild);
            } else {
                tmpltChild.setRegistId("ENS_SYS");
                tmpltMngKkoAlimtalkMapper.add(tmpltChild);
            }
        }

        if (!CmmnUtil.isEmpty(dto.getKkoMydoc())) {
            TmpltMngKkoMydocMapper mapper = Mappers.getMapper(TmpltMngKkoMydocMapper.class);
            TmpltMngKkoMydoc tmpltChild = mapper.toEntity(dto.getKkoMydoc());
            if (tmpltMngKkoMydocMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) {
                tmpltChild.setUpdId("ENS_SYS");
                tmpltMngKkoMydocMapper.modify(tmpltChild);
            } else {
                tmpltChild.setRegistId("ENS_SYS");
                tmpltMngKkoMydocMapper.add(tmpltChild);
            }
        }

        if (!CmmnUtil.isEmpty(dto.getNvSigntalk())) {
            TmpltMngNvSigntalkMapper mapper = Mappers.getMapper(TmpltMngNvSigntalkMapper.class);
            TmpltMngNvSigntalk tmpltChild = mapper.toEntity(dto.getNvSigntalk());
            if (tmpltMngNvSigntalkMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) {
                tmpltChild.setUpdId("ENS_SYS");
                tmpltMngNvSigntalkMapper.modify(tmpltChild);
            } else {
                tmpltChild.setRegistId("ENS_SYS");
                tmpltMngNvSigntalkMapper.add(tmpltChild);
            }
        }

//        super.deleteCache(redisTemplate, dto.getOrgCd(), dto.getTmpltCd());
    }

    private void toMappedChildTmpltMng(TmpltMngIntgrnDTO dto, TmpltMngDTO childDto) {
        childDto.setOrgCd(dto.getOrgCd());
        childDto.setTmpltCd(dto.getTmpltCd());
        childDto.setTitle(dto.getTitle());
        childDto.setMessage(dto.getMessage());
        childDto.setUseYn(dto.getUseYn());
    }
}
