package com.lingniu.ingest.protocol.jt808;

import com.lingniu.ingest.session.DeviceSession;
import com.lingniu.ingest.session.SessionStore;

import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.UnaryOperator;

public final class TestSessionStore implements SessionStore {

    private final ConcurrentMap<String, DeviceSession> byId = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, String> vinToId = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, String> phoneToId = new ConcurrentHashMap<>();

    @Override
    public void put(DeviceSession session) {
        byId.put(session.sessionId(), session);
        if (session.vin() != null) {
            vinToId.put(session.vin(), session.sessionId());
        }
        if (session.phone() != null) {
            phoneToId.put(session.phone(), session.sessionId());
        }
    }

    @Override
    public Optional<DeviceSession> findBySessionId(String sessionId) {
        return Optional.ofNullable(byId.get(sessionId));
    }

    @Override
    public Optional<DeviceSession> findByVin(String vin) {
        String sessionId = vinToId.get(vin);
        return sessionId == null ? Optional.empty() : findBySessionId(sessionId);
    }

    @Override
    public Optional<DeviceSession> findByPhone(String phone) {
        String sessionId = phoneToId.get(phone);
        return sessionId == null ? Optional.empty() : findBySessionId(sessionId);
    }

    @Override
    public synchronized Optional<DeviceSession> update(String sessionId, UnaryOperator<DeviceSession> updater) {
        DeviceSession current = byId.get(sessionId);
        if (current == null) {
            return Optional.empty();
        }
        DeviceSession next = updater.apply(current);
        put(next);
        return Optional.of(next);
    }

    @Override
    public void remove(String sessionId) {
        DeviceSession removed = byId.remove(sessionId);
        if (removed == null) {
            return;
        }
        if (removed.vin() != null) {
            vinToId.remove(removed.vin(), sessionId);
        }
        if (removed.phone() != null) {
            phoneToId.remove(removed.phone(), sessionId);
        }
    }

    @Override
    public int size() {
        return byId.size();
    }
}
