#ifndef HOSTS_PUBLISHER_H
#define HOSTS_PUBLISHER_H

#include <cstdint>
#include <deque>
#include <memory>

#include "core/time.h"
#include "core/types.h"
#include "core/host.h"
#include "core/simulator.h"
#include "hosts/mgmt_msg.h"
#include "hosts/policies.h"

namespace dofs {

class Publisher final : public Host {
public:
        Publisher(Simulator* sim,
                  NodeId id,
                  Time update_latency_base,
                  std::unique_ptr<PubBasePolicy> policy,
                  Time mgmt_latency) noexcept;

        // Triggered by workload driver
        void recv_update(Bytes size, PacketGroups update_groups_mask) noexcept;

        // Status with latency clamp; new_latency==0 means "no change"
        void set_status(NodeStatus s, Time new_latency = Time{}) noexcept;

        // Mgmt-plane receive (from subscribers)
        virtual void recv_mgmt_msg(MgmtMsgPtr msg) noexcept override;

        // Host overrides (data-plane callbacks)
        virtual void recv_flow(NodeId src, FlowId flow, FlowPriority prio,
                               Bytes flow_size) override;
        virtual void recv_frame(const Packet& frame) override;

        // Telemetry
        uint64_t updates_in()  const noexcept {
                return _updates_in;
        }
        uint64_t bytes_out()   const noexcept {
                return _bytes_out;
        }

private:
        enum class State : uint8_t { Idle = 0, Staging = 1, Quiesced = 2 };

        struct Pending {
                Bytes         size{0};
                PacketGroups  mask{0};
                Time          enq_time{};
        };

        void arm_staging_if_needed() noexcept;
        void on_staging_timer() noexcept;

private:
        Simulator *const               _sim;
        Time                           _update_latency_base;
        Time                           _update_latency_cur;
        Time                           _mgmt_latency;
        std::unique_ptr<PubBasePolicy> _policy;

        State                         _state{State::Idle};
        EventId                       _staging_evt{NULL_EVENT};
        std::deque<Pending>           _queue;

        // telemetry
        uint64_t _updates_in{0};
        uint64_t _bytes_out{0};
        uint64_t _mgmt_in{0};
        uint64_t _mgmt_out{0};
};

} // namespace dofs

#endif // HOSTS_PUBLISHER_H
