#include "network/switch/ecn_dedicated_red.h"

#include <algorithm>
#include <cmath>

namespace dofs {

Packet &DedicatedREDEngine::process_packet(Packet &pkt,
                SwitchBuffer* buf) noexcept {
        if (!buf)
                return pkt;

        const PortId  port = pkt.dst_port();
        const uint16_t pc  = buf->port_cnt();

        if (port >= pc)
                return pkt;

        ensure_size(pc);

        // instantaneous queue (bytes) for the egress port
        const double q_inst = static_cast<double>(buf->port_buffered(port));
        double &q_avg       = _avg_bytes[port];
        q_avg               = ewma(q_inst, q_avg);

        const double min_th = static_cast<double>(_min_th);
        const double max_th = static_cast<double>(_max_th);

        if (q_avg <= min_th) {
                // Below min_th: no marking
                return pkt;
        }

        if (q_avg >= max_th) {
                // Above max_th: trim (replace drop)
                header_trim(pkt, _back_to_sender);
                return pkt;
        }

        // Between thresholds: mark ECN with probability p(q)
        const double p = _p_max * (q_avg - min_th) / std::max(1.0, (max_th - min_th));

        if (_rng && _rng->uniform01() < p) {
                maybe_mark_ecn(pkt);
        }

        return pkt;
}

} // namespace dofs
