package com.lingniu.ingest.protocol.jt808.session;

import com.lingniu.ingest.protocol.jt808.model.Jt808Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 下行命令的请求/应答同步匹配表。
 *
 * <p>调用 {@link #await(String, int)} 时注册一个 {@link CompletableFuture}，
 * 对应 key = {@code phone + ':' + serial}；当 {@code Jt808ChannelHandler} 收到 0x0001 通用应答
 * 或其它同步应答消息时调用 {@link #complete(String, int, Jt808Message)} 触发 future 完成。
 */
public final class Jt808PendingRequests {

    private static final Logger log = LoggerFactory.getLogger(Jt808PendingRequests.class);

    private final ConcurrentMap<String, CompletableFuture<Jt808Message>> pending = new ConcurrentHashMap<>();

    public CompletableFuture<Jt808Message> await(String phone, int serial) {
        CompletableFuture<Jt808Message> cf = new CompletableFuture<>();
        // JT808 平台下行流水号按终端 phone 独立递增，因此 phone+serial 才能唯一定位一次请求。
        pending.put(key(phone, serial), cf);
        return cf;
    }

    public void complete(String phone, int serial, Jt808Message response) {
        CompletableFuture<Jt808Message> cf = pending.remove(key(phone, serial));
        if (cf != null) {
            cf.complete(response);
        } else {
            log.debug("no pending request for phone={} serial={}", phone, serial);
        }
    }

    public void cancel(String phone, int serial) {
        CompletableFuture<Jt808Message> cf = pending.remove(key(phone, serial));
        if (cf != null) cf.cancel(true);
    }

    public int size() {
        return pending.size();
    }

    private static String key(String phone, int serial) {
        return phone + ":" + serial;
    }
}
