package com.seer.teach.netty.im.manager;

import com.seer.teach.netty.common.dto.Pending;

import java.io.IOException;
import java.nio.channels.Channel;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 管理“待ACK”的下行消息
 */
public class PendingAckManager {

    /**
     * 存储所有待确认消息的并发安全映射表
     */
    private static final ConcurrentMap<String, Pending> PENDING = new ConcurrentHashMap<>();

    /**
     * 添加一个待确认的消息项到管理器中
     *
     * @param p 待添加的Pending对象
     */
    public static void put(Pending p) {
        PENDING.put(p.msgId, p);
    }

    /**
     * 根据消息ID移除并返回对应的Pending对象
     *
     * @param msgId 消息ID
     * @return 对应的Pending对象，如果不存在则返回null
     */
    public static Pending remove(String msgId) {
        return PENDING.remove(msgId);
    }

    /**
     * 根据消息ID获取对应的Pending对象（不移除）
     *
     * @param msgId 消息ID
     * @return 对应的Pending对象，如果不存在则返回null
     */
    public static Pending get(String msgId) {
        return PENDING.get(msgId);
    }

    /**
     * 完成指定消息的确认处理，并通知Promise结果
     *
     * @param fromMsgId 消息ID
     * @param ok        确认是否成功，true表示成功，false表示失败
     */
    public static void complete(String fromMsgId, boolean ok) {
        Pending p = remove(fromMsgId);
        if (p != null) {
            // 取消超时任务
            if (p.timeoutTask != null) p.timeoutTask.cancel(false);
            // 通知Promise结果
            p.promise.trySuccess(ok);
        }
    }

    /**
     * 关闭指定通道上所有待确认的消息，并标记为失败
     *
     * @param ch     目标通道
     * @param reason 失败原因描述
     */
    public static void failAllOf(Channel ch, String reason) {
        // 遍历所有待确认消息，找出属于该通道的项
        for (Map.Entry<String, Pending> e : PENDING.entrySet()) {
            Pending p = e.getValue();
            if (p.channel == ch) {
                // 原子性地移除该项并取消超时任务
                if (PENDING.remove(p.msgId, p)) {
                    if (p.timeoutTask != null) p.timeoutTask.cancel(false);
                    p.promise.tryFailure(new IOException("Channel closed: " + reason));
                }
            }
        }
    }
}
