package com.njcn.shiro.session.impl;


import com.njcn.pojo.commons.RedisDB;
import com.njcn.shiro.session.UserSessionManager;
import com.njcn.shiro.session.UserShiroSessionRepository;
import com.njcn.sso.shiro.session.SessionStatus;
import com.njcn.utils.SerializeUtil;
import com.njcn.utils.redis.JedisManager;
import org.apache.shiro.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * shiro用户的Session缓存管理
 */
public class JedisShiroSessionRepository implements UserShiroSessionRepository {

    private static final Logger logger = LoggerFactory.getLogger(JedisShiroSessionRepository.class);

    public static final String REDIS_SHIRO_SESSION = "shiro-session:";

    public static final String REDIS_SHIRO_ALL = "*shiro-session:*";

    private JedisManager jedisManager;

    /**
     * 保存session进redis,包括每次用户后台访问时，更新session在redis中的生存时间
     *
     * @param session 指定会话
     */
    @Override
    public void saveSession(Session session) {
        if (session == null || session.getId() == null) throw new NullPointerException("session is empty");
        try {
            byte[] key = SerializeUtil.serialize(buildRedisSessionKey(session.getId()));
            if (null == session.getAttribute(UserSessionManager.SESSION_STATUS)) {
                SessionStatus sessionStatus = new SessionStatus();
                sessionStatus.setOnlineStatus(Boolean.TRUE);
                session.setAttribute(UserSessionManager.SESSION_STATUS, sessionStatus);
            }
            byte[] value = SerializeUtil.serialize(session);
            long sessionTimeOut = session.getTimeout() / 1000;
            Long expireTime;
            if (sessionTimeOut > RedisDB.SESSION_DB_TIME) {
                expireTime = Long.valueOf(RedisDB.SESSION_DB_TIME);
            } else if (sessionTimeOut <= 0) {
                expireTime = -1L;
            } else {
                expireTime = sessionTimeOut + 60;
            }
            jedisManager.saveValueByKey(RedisDB.SESSION_DB, key, value, expireTime.intValue());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("保存session进redis异常，异常为" + e.toString());
        }
    }

    /**
     * 从Redis中将指定的会话清除，当会话终止、会话过期时执行。
     *
     * @param id 会话ID
     */
    @Override
    public void deleteSession(Serializable id) {
        if (id == null) {
            throw new NullPointerException("session id is empty");
        }
        try {
            if (id.toString().contains("session")) {
                jedisManager.deleteByKey(RedisDB.SESSION_DB, SerializeUtil.serialize(id));
            } else {
                jedisManager.deleteByKey(RedisDB.SESSION_DB, SerializeUtil.serialize(buildRedisSessionKey(id)));
            }
        } catch (Exception e) {
            logger.error("从redis中清除指定的session失败，session的ID为" + "id,异常为" + e.toString());
        }
    }

    /**
     * 根据指定ID获取指定会话
     *
     * @param id 会话ID
     */
    @Override
    public Session getSession(Serializable id) {
        if (id == null) throw new NullPointerException("session id is empty");
        Session session = null;
        try {
            byte[] value;
            if (id.toString().contains("session")) {
                value = jedisManager.getValueByKey(RedisDB.SESSION_DB, SerializeUtil.serialize(id));
            } else {
                value = jedisManager.getValueByKey(RedisDB.SESSION_DB, SerializeUtil.serialize(buildRedisSessionKey(id)));
            }
            session = SerializeUtil.deserialize(value, Session.class);
        } catch (Exception e) {
            logger.error("根据指定的sessionID，获取会话失败，session的ID为" + "id,异常为" + e.toString());
        }
        return session;
    }

    /**
     * 获取redis中所有的会话
     *
     * @return 会话集合
     */
    @Override
    public Collection<Session> getAllSessions() {
        Jedis jedis = null;
        Set<Session> sessions = new HashSet<>();
        try {
            jedis = jedisManager.getJedis();
            jedis.select(RedisDB.SESSION_DB);
            Set<byte[]> byteKeys = jedis.keys((JedisShiroSessionRepository.REDIS_SHIRO_ALL).getBytes());
            if (byteKeys != null && byteKeys.size() > 0) {
                for (byte[] bs : byteKeys) {
                    Session obj = SerializeUtil.deserialize(jedis.get(bs), Session.class);
                    if (obj instanceof Session) {
                        sessions.add(obj);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("获取所有的session失败，异常为：" + e.toString());
        } finally {
            if (null != jedis) jedisManager.returnResource(jedis);
        }
        return sessions;
    }


    /**
     * 根据sessionID生成当前系统身份的key
     *
     * @param sessionId 会话ID
     * @return key值
     */
    private String buildRedisSessionKey(Serializable sessionId) {
        return REDIS_SHIRO_SESSION + sessionId;
    }


    public JedisManager getJedisManager() {
        return jedisManager;
    }

    public void setJedisManager(JedisManager jedisManager) {
        this.jedisManager = jedisManager;
    }


    /**
     * 激活当前会话，并更新redis中该会话的生命周期
     */
    @Override
    public void activeSession(Session session) {
        if (null == session) {
            return;
        }
        session.touch();
        this.saveSession(session);
    }

}
