// pcs_usm_component_skeleton.cc
//
// SST-Core integration collateral for the OCaml model.  This file is not built
// by the package test suite because SST-Core is intentionally not vendored here.
// It shows how the OCaml event vocabulary maps to a future SST Component.

#include <sst/core/component.h>
#include <sst/core/event.h>
#include <sst/core/link.h>
#include <sst/core/params.h>
#include <sst/core/sst_config.h>

#include <cstdint>
#include <string>

namespace pcs_usm {

class StorageEvent : public SST::Event {
public:
    enum Kind : uint8_t {
        WorkloadArrival,
        AdmissionDecision,
        MetadataLookup,
        GpuKernelSubmit,
        RdmaPacketBatch,
        ZfsTxgWrite,
        ZfsTxgStateTransition,
        ScaleEvaluate,
        ScaleApply,
        BackpressureSignal
    };

    StorageEvent() = default;
    StorageEvent(Kind k, uint64_t bytes, std::string detail)
        : kind(k), bytes(bytes), detail(std::move(detail)) {}

    Kind kind{WorkloadArrival};
    uint64_t bytes{0};
    std::string detail;

    void serialize_order(SST::Core::Serialization::serializer& ser) override {
        SST::Event::serialize_order(ser);
        ser & kind;
        ser & bytes;
        ser & detail;
    }

    ImplementSerializable(pcs_usm::StorageEvent);
};

class StorageComponent : public SST::Component {
public:
    SST_ELI_REGISTER_COMPONENT(
        StorageComponent,
        "pcs_usm",
        "StorageComponent",
        SST_ELI_ELEMENT_VERSION(0, 1, 0),
        "PCS/USM storage simulation component skeleton",
        COMPONENT_CATEGORY_PROCESSOR
    )

    SST_ELI_DOCUMENT_PARAMS(
        {"role", "Component role: scheduler|rdma|roce|gpu|zfs|metadata|scaler", "scheduler"},
        {"tick_ns", "Component tick in ns", "1000"}
    )

    SST_ELI_DOCUMENT_PORTS(
        {"in", "Inbound events", {"pcs_usm.StorageEvent"}},
        {"out", "Outbound events", {"pcs_usm.StorageEvent"}},
        {"metrics", "Metric/event feed", {"pcs_usm.StorageEvent"}}
    )

    StorageComponent(SST::ComponentId_t id, SST::Params& params)
        : SST::Component(id), role(params.find<std::string>("role", "scheduler")) {
        in = configureLink("in", new SST::Event::Handler2<StorageComponent, &StorageComponent::handleEvent>(this));
        out = configureLink("out");
        metrics = configureLink("metrics");
        registerAsPrimaryComponent();
        primaryComponentDoNotEndSim();
    }

    void setup() override {}
    void finish() override { primaryComponentOKToEndSim(); }

private:
    std::string role;
    SST::Link* in{nullptr};
    SST::Link* out{nullptr};
    SST::Link* metrics{nullptr};

    void handleEvent(SST::Event* ev) {
        auto* storage_event = dynamic_cast<StorageEvent*>(ev);
        if (!storage_event) {
            delete ev;
            return;
        }

        // Future integration point:
        // - RDMA role: apply RoCE-v2 packet model and emit RdmaPacketBatch metrics.
        // - GPU role: apply kernel duration model and emit GpuKernelSubmit metrics.
        // - ZFS role: apply TXG state machine and emit ZfsTxgStateTransition.
        // - Scaler role: evaluate rolling p99s and emit ScaleApply.

        if (metrics) {
            metrics->send(new StorageEvent(*storage_event));
        }
        if (out) {
            out->send(storage_event);
        } else {
            delete storage_event;
        }
    }
};

} // namespace pcs_usm
