package cn.wisenergy.shiro.util.redis;

import cn.wisenergy.common.utils.ByteUtil;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: nh
 * @create: 2021-04-07 11:07
 **/
public class RedisSessionDao extends AbstractSessionDAO {

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String REDIS_SESSION_PREFIX = "SHIRO_SESSION";

    private static final long EXPIRE_TIME = 30 * 60;

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        this.saveSession(session);
        return sessionId;
    }

    private void saveSession(Session session) {
        if (session == null || session.getId() == null) {
            return;
        }
        redisTemplate.opsForValue().set(getRedisSessionPrefix(session.getId()), session, EXPIRE_TIME, TimeUnit.SECONDS);
    }

    String getRedisSessionPrefix(Serializable sessionId) {
        return REDIS_SESSION_PREFIX + sessionId;
    }


    @Override
    protected Session doReadSession(Serializable sessionId) {
        Object o = redisTemplate.opsForValue().get(getRedisSessionPrefix(sessionId));
        return (Session) o;
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session);
    }

    @Override
    public void delete(Session session) {
        redisTemplate.delete(getRedisSessionPrefix(session.getId()));
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<>();

        Set<byte[]> keys = null;
        try {
            redisTemplate.keys(ByteUtil.objectToBytes(REDIS_SESSION_PREFIX + "*"));

        } catch (IOException e) {
            e.printStackTrace();
        }
        if (keys != null && keys.size() > 0) {
            for (byte[] key : keys) {
                Session s = null;
                try {
                    s = (Session) ByteUtil.bytesToObject((byte[]) redisTemplate.opsForValue().get(key));
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                sessions.add(s);
            }
        }

        return sessions;
    }
}
