package com.brilliance.isc.common.codetable.service.impl;

import com.brilliance.isc.bo.Stb;
import com.brilliance.isc.common.codetable.service.CodetableService;
import com.brilliance.isc.common.util.StringUtils;
import com.brilliance.isc.mda.dao.CodetableMapper;
import com.brilliance.isc.vo.manager.DicVo;
import com.brilliance.mda.runtime.mda.CodetableItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service
public class CodetableServiceImpl implements CodetableService {

    private static Logger log = LoggerFactory.getLogger(CodetableServiceImpl.class);

    @Autowired
    @Qualifier("jacksonRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private CodetableMapper codetableMapper;

    // 默认语种为EN
    private static final String DEFAULT_UIL = "EN";

    private static final String CN_UIL = "CN";

    private static final String SEPARATOR = "-";

    private static final String SRT_SORT = "SRT";

    private static final String COD_SORT = "COD";

    private static final String TYPE = "STB";

    private static final long EXPIRETIMES = 360l;

    private static final TimeUnit EXPIRETYPE = TimeUnit.SECONDS;

    @Transactional
    @Override
    public String saveDicInfo(DicVo dicVo) {
        Stb stb = new Stb();
        stb.setTbl(dicVo.getCodeType());
        stb.setTxt(dicVo.getCodeName());
        stb.setCod(dicVo.getCodeValue());
        List<Stb> stbList = codetableMapper.listAllByCod(stb);
        // 看是否包含EN 、CN,如果包含，则修改；如果不包含，则新增
        boolean enFlag = stbList.stream().anyMatch(item -> DEFAULT_UIL.equalsIgnoreCase(item.getUil()));
        if (enFlag) {
            stb.setUil(DEFAULT_UIL);
            codetableMapper.updateTxt(stb);
        } else {
            stb.setUil(DEFAULT_UIL);
            int maxSrt = codetableMapper.getMaxSrtByTblAndCod(stb);
            stb.setSrt(maxSrt + 1);
            codetableMapper.insert(stb);
        }
        boolean cnFlag = stbList.stream().anyMatch(item -> CN_UIL.equalsIgnoreCase(item.getUil()));
        if (cnFlag) {
            stb.setUil(CN_UIL);
            codetableMapper.updateTxt(stb);
        } else {
            stb.setUil(CN_UIL);
            int maxSrt = codetableMapper.getMaxSrtByTblAndCod(stb);
            stb.setSrt(maxSrt + 1);
            codetableMapper.insert(stb);
        }
        return "{\"success\":\"保存成功！\"}";
    }

    @Transactional
    @Override
    public String deleteDicInfo(DicVo dicVo) {
        Stb stb = new Stb();
        stb.setTbl(dicVo.getCodeType());
        stb.setCod(dicVo.getCodeValue());
        List<Stb> stbList = codetableMapper.listAllByCod(stb);
        for (Stb item : stbList) {
            stb.setUil(item.getUil());
            codetableMapper.delete(stb);
        }
        return "{\"success\":\"删除成功！\"}";
    }

    @Override
    public DicVo getDicInfo(DicVo dicVo) {
        Stb stb = getStbByDicVo(dicVo);
        Stb result = codetableMapper.selectByCod(stb);
        if (result == null) {
            return null;
        }
        return getDicVoByStb(result);
    }

    @Override
    public List<DicVo> listDicInfo(DicVo dicVo) {
        List<Stb> stbList;
        Stb stb = getStbByDicVo(dicVo);
        String key = generateKey(stb.getTbl() + "_" + stb.getUil() + "_" + stb.getSrt());
        ArrayList<DicVo> result = (ArrayList<DicVo>) redisTemplate.opsForValue().get(key);
        if (result == null) {
            if (SRT_SORT.equalsIgnoreCase(dicVo.getSort())) {
                stbList = codetableMapper.listFuzzyByRecordOrderBySrt(stb);
            } else {
                // 默认按照 cod 字段排序
                stbList = codetableMapper.listFuzzyByRecord(stb);
            }
            result = new ArrayList<>();
            for (Stb item : stbList) {
                DicVo vo = getDicVoByStb(item);
                if (SRT_SORT.equalsIgnoreCase(dicVo.getSort())) {
                    vo.setSort(SRT_SORT);
                } else {
                    vo.setSort(COD_SORT);
                }
                result.add(vo);
            }
            redisTemplate.opsForValue().set(key, result, EXPIRETIMES, EXPIRETYPE);
            return result;
        }else{
            return result;
        }
    }

    @Override
    public List<CodetableItem> selectList(String tbl, String lang) {
        String key = generateKey(tbl + SEPARATOR + lang);
        List<CodetableItem> codetableItems = (List<CodetableItem>) redisTemplate.opsForValue().get(key);
        if (codetableItems == null) {
            codetableItems = new ArrayList<>();
            log.debug("Redis中不存在key：" + key + "或者已经过期，查数据库");
            List<Stb> stbs = codetableMapper.selectList(tbl, lang);
            for (Stb stb : stbs) {
                codetableItems.add(new CodetableItem(stb.getTxt(), stb.getCod()));
            }
            redisTemplate.opsForValue().set(key, codetableItems, EXPIRETIMES, EXPIRETYPE);
            return codetableItems;
        } else {
            log.debug("Redis中存在key：" + key + "直接返回");
            return codetableItems;
        }
    }

    private String generateKey(String key) {
        return TYPE + "_" + key;
    }

    @Override
    public List<CodetableItem> selectList(String tbl) {
        return selectList(tbl, DEFAULT_UIL);
    }

    @Override
    public List<String> getTblKeyList(String tbl, String lang) {
        List<CodetableItem> codetableItems = selectList(tbl, lang);
        return codetableItems.stream().map(CodetableItem::getValue).collect(Collectors.toList());
    }

    @Override
    public List<String> getTblKeyList(String tbl) {
        return getTblKeyList(tbl, DEFAULT_UIL);
    }

    public List<String> getTblKeyListBySrtAsc(String tbl) {
        List<Stb> stbs = codetableMapper.selectByTblOrderBySrtAsc(tbl, DEFAULT_UIL);
        return stbs.stream().map(Stb::getCod).collect(Collectors.toList());
    }

    @Override
    public String getTblKey(String label, String tbl, String lang) {
        List<CodetableItem> codetableItems = selectList(tbl, lang);
        Optional<CodetableItem> optionalCodetableItem = codetableItems.stream().filter(item -> item.getLabel().equals(label)).findFirst();
        String value = "";
        if (optionalCodetableItem.isPresent()) {
            value = optionalCodetableItem.get().getValue();
        }
        return value;
    }

    @Override
    public String getTblKey(String label, String tbl) {
        return getTblKey(label, tbl, DEFAULT_UIL);
    }

    @Override
    public String getTblLabel(String value, String tbl, String lang) {
        List<CodetableItem> codetableItems = selectList(tbl, lang);
        Optional<CodetableItem> optionalCodetableItem = codetableItems.stream().filter(item -> item.getValue().equals(value)).findFirst();
        String label = "";
        if (optionalCodetableItem.isPresent()) {
            label = optionalCodetableItem.get().getLabel();
        }
        return label;
    }

    @Override
    public String getTblLabelNoUseCache(String value, String tbl) {
        return getTblLabelNoUseCache(value, tbl, DEFAULT_UIL);
    }

    @Override
    public String getTblLabelNoUseCache(String value, String tbl, String lang) {
        List<Stb> stbs = codetableMapper.selectList(tbl, lang);
        Optional<Stb> first = stbs.stream().filter(item -> item.getCod().equalsIgnoreCase(value)).findFirst();
        String label = "";
        if (first.isPresent()) {
            label = first.get().getTxt();
        }
        return label;
    }

    @Override
    public List<Stb> getStbFromDb(Stb stb) {
        return codetableMapper.selectList(stb.getTbl(), stb.getUil());
    }

    @Override
    public String getTblLabel(String value, String tbl) {
        return getTblLabel(value, tbl, DEFAULT_UIL);
    }

    private Stb getStbByDicVo(DicVo dicVo) {
        Stb stb = new Stb();
        stb.setTbl(dicVo.getCodeType());
        stb.setTxt(dicVo.getCodeName());
        if (StringUtils.isEmpty(dicVo.getUil())) {
            stb.setUil(DEFAULT_UIL);
        } else {
            stb.setUil(dicVo.getUil());
        }
        stb.setCod(dicVo.getCodeValue());
        return stb;
    }

    private DicVo getDicVoByStb(Stb stb) {
        DicVo dicVo = new DicVo();
        dicVo.setCodeType(stb.getTbl());
        dicVo.setCodeName(stb.getTxt());
        dicVo.setUil(stb.getUil());
        dicVo.setCodeValue(stb.getCod());
        return dicVo;
    }

}
