package aceboot::observability

import std.collection.*

/**
 * MDC(Mapped Diagnostic Context):协程本地诊断上下文。
 * 由 requestId() 中间件写入,Logger.format() 自动附加到每条日志。
 * 无请求上下文时(启动日志、定时任务)getAll() 返回空数组,不影响正常输出。
 *
 * 生命周期:requestId() 中间件在 next() 前 set("requestId", id),
 * finally 块中 clear()——保证协程复用时不泄漏上一请求的上下文。
 */
public class Mdc {
    private static let holder = ThreadLocal<HashMap<String, String>>()

    private init() {}

    /** 设置当前协程的 MDC 键值。键不存在则新建,已存在则覆盖。 */
    public static func set(key: String, value: String): Unit {
        match (holder.get()) {
            case Some(map) => map.add(key, value)
            case None =>
                let map = HashMap<String, String>()
                map.add(key, value)
                holder.set(map)
        }
    }

    /** 读取当前协程的 MDC 值;无该键或无 MDC 上下文时返回 None。 */
    public static func get(key: String): ?String {
        match (holder.get()) {
            case Some(map) => map.get(key)
            case None => None
        }
    }

    /**
     * 返回当前协程所有 MDC 键值对的快照数组。
     * Logger.format() 调用此方法将 MDC 字段附加到 JSON 输出末尾。
     * 无请求上下文(或已 clear)时返回空数组,Logger 不会附加任何额外字段。
     */
    public static func getAll(): Array<(String, String)> {
        match (holder.get()) {
            case Some(map) =>
                let arr = ArrayList<(String, String)>()
                for ((k, v) in map) {
                    arr.add((k, v))
                }
                arr.toArray()
            case None => []
        }
    }

    /** 删除当前协程中的指定 MDC 键。 */
    public static func remove(key: String): Unit {
        match (holder.get()) {
            case Some(map) => map.remove(key)
            case None => ()
        }
    }

    /**
     * 清除当前协程的全部 MDC 上下文。
     * requestId() 中间件在 finally 块中调用,确保协程复用安全。
     */
    public static func clear(): Unit {
        holder.set(None)
    }
}