package cokr.xit.ens.modules.nvsigntalk.service.strategy;

import cokr.xit.ens.core.exception.EnsException;
import cokr.xit.ens.core.exception.code.EnsErrCd;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng;
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.nvsigntalk.domain.TmpltMngNvSigntalk;
import cokr.xit.ens.modules.nvsigntalk.domain.repository.TmpltMngNvSigntalkRepository;
import cokr.xit.ens.modules.nvsigntalk.model.TmpltMngNvSigntalkDTO;
import cokr.xit.ens.modules.nvsigntalk.model.struct.TmpltMngNvSigntalkMapper;
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_nvst")
@RequiredArgsConstructor
public class TmpltMngStrategyNvSigntalk extends TmpltMngStrategyTemplate<Map<String, Object>, TmpltMngNvSigntalkDTO> {

    private final OrgMngRepository orgMngRepository;
    private final TmpltMngRepository tmpltMngRepository;
    private final TmpltMngNvSigntalkRepository tmpltMngNvSigntalkRepository;
    private TmpltMngNvSigntalkMapper nvSigntalkMapper = Mappers.getMapper(TmpltMngNvSigntalkMapper.class);
//    private final RedisTemplate redisTemplate;

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

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

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


    @Override
    protected TmpltMngNvSigntalkDTO validate(Map<String, Object> params) {
        try {
            TmpltMngNvSigntalkDTO dto = mapper.convertValue(params, TmpltMngNvSigntalkDTO.class);

            final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
            Set<ConstraintViolation<TmpltMngNvSigntalkDTO>> 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(TmpltMngNvSigntalkDTO.class.getDeclaredFields()).map(row -> row.getName()).collect(Collectors.toList()));
            throw new EnsException(EnsErrCd.ERR403, "유효하지 않은 파라미터 입니다. 사용가능한 파라미터는 resultInfo 를 참고하시기 바랍니다.", fields);
        }
    }

    @Override
    protected void addProc(TmpltMngNvSigntalkDTO 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()));
                });

        TmpltMngNvSigntalk tmpltMng = nvSigntalkMapper.toEntity(dto);
        tmpltMng.setOrgMng(orgMng);
        tmpltMng.setRegistId("ENS_SYS");
        tmpltMngNvSigntalkRepository.save(tmpltMng);
    }

    @Override
    protected void modifyProc(TmpltMngNvSigntalkDTO dto) {
        TmpltMngNvSigntalk tmpltMng = tmpltMngNvSigntalkRepository.findFetchByOrgCdAndTmpltCd((dto).getOrgCd(), (dto).getTmpltCd())
                .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s) 및 템플릿코드(%s)가 일치하는 자료가 없습니다.", dto.getOrgCd(), dto.getTmpltCd())));
        if(!"Y".equals(tmpltMng.getUseYn()))
            throw new EnsException(EnsErrCd.ERR402, "\"미사용\" 상태의 템플릿은 수정 할 수 없습니다.");
        nvSigntalkMapper.updateFromDto(dto, tmpltMng);
        tmpltMng.setUpdId("ENS_SYS");

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