package dst.ass1.kv.impl;

import dst.ass1.kv.ISessionManager;
import dst.ass1.kv.SessionCreationFailedException;
import dst.ass1.kv.SessionNotFoundException;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.UUID;

public class SessionManager implements ISessionManager {
    // "sUser:${userId}" -> UUID - Reverse-sessiondata-userId-mapping.
    private final static String SUSER = "sUser:";
    //  "sData:${UUID}" -> hashmap - Sessiondata.
    private final static String SDATA = "sData:";

    private final Jedis jedis; // no lightsabers :(

    public SessionManager(String host, int port) {
        jedis = new Jedis(host, port);
    }

    @Override
    public String createSession(Long userId, int timeToLive) throws SessionCreationFailedException {
        jedis.del(SUSER + userId.toString());
        return requireSession(userId, timeToLive);
    }

    @Override
    public void setSessionVariable(String sessionId, String key, String value) throws SessionNotFoundException {
        if (!jedis.exists(SDATA + sessionId)) throw new SessionNotFoundException("Unknown sessionId:" + sessionId);
        jedis.hset(SDATA + sessionId, key, value);
    }

    @Override
    public String getSessionVariable(String sessionId, String key) throws SessionNotFoundException {
        if (!jedis.exists(SDATA + sessionId)) throw new SessionNotFoundException("Unknown sessionId:" + sessionId);
        return jedis.hget(SDATA + sessionId, key);
    }

    @Override
    public Long getUserId(String sessionId) throws SessionNotFoundException {
        if (!jedis.exists(SDATA + sessionId)) throw new SessionNotFoundException("Unknown sessionId:" + sessionId);
        return Long.valueOf(jedis.hget(SDATA + sessionId, "userId"));
    }

    @Override
    public int getTimeToLive(String sessionId) throws SessionNotFoundException {
        if (!jedis.exists(SDATA + sessionId)) throw new SessionNotFoundException("Unknown sessionId:" + sessionId);
        return jedis.ttl(SDATA + sessionId).intValue();
    }

    @Override
    public String requireSession(Long userId, int timeToLive) throws SessionCreationFailedException {
        String uuid = jedis.get(SUSER + userId.toString());
        if (uuid == null) {
            uuid = UUID.randomUUID().toString();
            jedis.watch(SUSER + userId.toString());
            Transaction t = jedis.multi();
            t.set(SUSER + userId.toString(), uuid);
            t.expire(SUSER + userId.toString(), timeToLive);
            t.hset(SDATA + uuid, "userId", userId.toString());
            t.expire(SDATA + uuid, timeToLive);
            t.exec();
        }
        return uuid;
    }

    @Override
    public void close() {
        jedis.close();
    }
}
