package com.ag.secp.platform.redis;

import com.ag.secp.platform.spring.SpringApplicationContext;
import com.wb.common.KvBean;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

import static java.util.concurrent.Executors.newFixedThreadPool;


/**
 * @description: redis基本操作
 * @author: WangNan
 * @create: 2018-8-23
 */
@Service
public class PushCodeToRedis implements PushToRedisInterface {

    private static StringBuffer kvSql;

    private static Logger logger = LoggerFactory.getLogger(PushCodeToRedis.class);
    @Autowired
    private JdbcTemplate jdbcTemplatebusiness;
    @Autowired
    private JdbcTemplate feeJdbcTemplate;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private RedisTemplate redisTemplate;

    private ExecutorService threads;

    /**
     * 该方法初始化，把Redis代码全部清空，然后重新放进去
     */
    @Override
    public void redisLoad() {
        //清空  KVBUFF_ 下所有键
        Set<String> keys = redisTemplate.keys("KVBUFF_" + "*");

        redisTemplate.delete(keys);
        String[] jndis = {"default"};
        List<KvBean> allList = new ArrayList<>();
        for (String jndi : jndis) {

            //给静态StringBuffer赋值
            getSqlS(jndi);
            String sql = "SELECT * FROM(" + kvSql.toString() + ")   ORDER BY KEY_NAME,K";
            List<KvBean> kvBeanList = buildKvBeanList(sql, jndi);
            allList.addAll(kvBeanList);
        }
        Map<String, List<KvBean>> kvMap = groupKvBeanList(allList);

        intoRedis(kvMap);

        logger.info("++++++++++++++++ Redis ready ++++++++++++++++");
        logger.info("             _._ \n" +
                "           _.-``__ ''-._\n" +
                "      _.-``    `.  `_.  ''-._\n" +
                "  .-`` .-```.  ```\\/    _.,_ ''-._\n" +
                " (    '      ,       .-`  | `,    )\n" +
                " |`-._`-...-` __...-.``-._|'` _.-'|\n" +
                " |    `-._   `._    /     _.-'    |\n" +
                "  `-._    `-._  `-./  _.-'    _.-' \n" +
                " |`-._`-._    `-.__.-'    _.-'_.-'|\n" +
                " |    `-._`-._        _.-'_.-'    |\n" +
                "  `-._    `-._`-.__.-'_.-'    _.-' \n"  +
                " |`-._`-._    `-.__.-'    _.-'_.-'|\n" +
                " |    `-._`-._        _.-'_.-'    |\n" +
                "  `-._    `-._`-.__.-'_.-'    _.-' \n" +
                "      `-._    `-.__.-'    _.-'\n" +
                "          `-._        _.-'\n" +
                "              `-.__.-'\n");

    }

    public List<?> getBeanListFromRedis(String keyName) {
        return SerializeUtil.unserializeForList((byte[]) redisUtil.get("KVBUFF_" + keyName));
    }

    @Override
    public List<KvBean> getKvListFromRedis(String KeyName) {
        return SerializeUtil.unserializeForList((byte[]) redisUtil.get("KVBUFF_" + KeyName));
    }

    /**
     * 通过查询数据库把 CODE_SET 这张表的  KVSQL  和 CODESQL给拼起来 放到顶部的两个StringBuffer  中，经过这个方法之后顶部的  kvsql就有了值
     *
     * @param jndi
     */
    private void getSqlS(String jndi) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;
        boolean jd = true;
        try {
            kvSql = new StringBuffer();
            conn = jdbcTemplatebusiness.getDataSource().getConnection();
            st = conn.createStatement();
            rs = st.executeQuery("SELECT  KV_SQL ,COD_SQL,JNDI FROM   CODE_SET where JNDI='"+jndi+"'  ORDER BY  JNDI,TABLE_NAME");
            while (rs.next()) {
                if (jd) {
                    kvSql.append(rs.getString("COD_SQL"));
                    jd = false;
                } else {
                    kvSql.append(" UNION ALL ").append(rs.getString("COD_SQL"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                Objects.requireNonNull(rs).close();
                Objects.requireNonNull(st).close();
                Objects.requireNonNull(conn).close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 构建了一个KvBean的集合：  KeyName, K, V
     *
     * @return
     */
    private List<KvBean> buildKvBeanList(String sql, String jndi) {
        if ("default".equals(jndi)) {
            return jdbcTemplatebusiness.query(sql, new BeanPropertyRowMapper(KvBean.class));
        }
//        if ("".equals(jndi)){
//            return feeJdbcTemplate.query(sql, new BeanPropertyRowMapper(KvBean.class));
//        }
        return null;
    }

    /**
     * 把  KeyName  —— List<KvBean> 放到 Redis中
     *
     * @param kvMap
     */
    @Override
    public void intoRedis(Map<String, List<KvBean>> kvMap) {
        for (Map.Entry<String, List<KvBean>> entry : kvMap.entrySet()) {
            putRedis(entry.getKey(), entry.getValue(), true);
        }
    }

    /**
     * 把List对象放入redis中、此处放弃了redisTemplate对list的操作redisTemplate.opsForList()，而使用Memcache的方式进行存储
     *
     * @param keyName
     * @param kvBeanList
     */
    @Override
    public void putRedis(String keyName, List<KvBean> kvBeanList, Boolean isInit) {
        threads = newFixedThreadPool(5);
        threads.execute(() -> {
            redisTemplate.opsForValue().set("KVBUFF_" + keyName, SerializeUtil.serialize(kvBeanList));
        });
        threads.shutdown();
    }

    public void putShipToRedis(String keyName, List<?> list, Boolean isInit) {
        threads = newFixedThreadPool(5);
        threads.execute(() -> {
            redisTemplate.opsForValue().set("KVBUFF_" + keyName, SerializeUtil.serialize(list));
        });
        threads.shutdown();
    }

    /**
     * 根据keyName 进行分组操作, 返回Map<String,List<KvBean>>  KeyName  —— List<KvBean>
     *
     * @param kvBeanList
     * @return
     */
    @Override
    public Map<String, List<KvBean>> groupKvBeanList(List<KvBean> kvBeanList) {
        return kvBeanList.stream().collect(Collectors.groupingBy(KvBean::getKeyName));
    }

    public static void upRedisService(HttpServletRequest request, HttpServletResponse response) {
        PushCodeToRedis redisBean = (PushCodeToRedis) SpringApplicationContext.getBean("pushCodeToRedis");
        redisBean.updateRedisListByKey(request.getParameter("keyName"));
    }

    public static void load(HttpServletRequest request, HttpServletResponse response) {
        PushCodeToRedis redisBean = (PushCodeToRedis) SpringApplicationContext.getBean("pushCodeToRedis");
        redisBean.redisLoad();
    }

    /**
     * 更新缓存,做集群之后这个方法需要改一下
     *
     * @param keyName
     */
    @Override
    public void updateRedisListByKey(String keyName) {
        threads = newFixedThreadPool(10);
        threads.submit(() -> {
            List<String> sql
                    = jdbcTemplatebusiness.queryForList("SELECT COD_SQL FROM CODE_SET" +
                    " WHERE TABLE_NAME='" + keyName + "'", String.class);
            if (!CollectionUtils.isEmpty(sql)) {
                List<KvBean> kvBeanList = buildKvBeanList(sql.get(0), "default");
                if (!CollectionUtils.isEmpty(kvBeanList)) {
                    redisTemplate.delete("KVBUFF_" + keyName);
                    putRedis(keyName, kvBeanList, false);
                }
            } else {
                List<KvBean> codeList
                        = buildKvBeanList("SELECT  SYS_CATEGORY AS KEY_NAME,SYS_KEY AS K,SYS_VALUE AS V, SYS_NAME AS COMV,TO_CHAR(SYS_SEQ) AS COMV2   FROM S_CODE WHERE SYS_CATEGORY='" + keyName + "'", "default");
                if (!CollectionUtils.isEmpty(codeList)) {
                    redisTemplate.delete("KVBUFF_" + keyName);
                    putRedis(keyName, codeList, false);
                } else {
                    List<KvBean> wbKeyList
                            = buildKvBeanList("SELECT KEY_NAME,TO_CHAR(K) AS K,TO_CHAR(V) AS V,KEY_ID AS COMV,KEY_ID AS COMV2  FROM WB_KEY WHERE KEY_NAME='" + keyName + "'", "default");
                    if (!CollectionUtils.isEmpty(wbKeyList)) {
                        redisTemplate.delete("KVBUFF_" + keyName);
                        putRedis(keyName, wbKeyList, false);
                    }
                }
            }
        });
        threads.shutdown();
    }
}
