// Actual ORT CPU inference + a teaching document adapter; not a real Office engine.
#include <onnxruntime_cxx_api.h>
#include <array>
#include <cassert>
#include <cmath>
#include <future>
#include <iostream>
#include <vector>
struct Proposal { int generation, revision; std::vector<float> values; };
struct Document {
    std::array<float,3> cells{0,0,0}, before{0,0,0};
    int revision=1, undoRevision=0;
    bool apply(const Proposal& proposal, int currentGeneration) {
        if(proposal.generation!=currentGeneration || proposal.revision!=revision || proposal.values.size()!=3) return false;
        std::array<float,3> staged{};
        for(int i=0;i<3;++i) {
            if(!std::isfinite(proposal.values[i])) return false;
            staged[i]=proposal.values[i];
        }
        before=cells; cells=staged; undoRevision=++revision; return true;
    }
    bool undo() {
        if(undoRevision!=revision) return false;
        cells=before; ++revision; undoRevision=0; return true;
    }
    void remoteEdit() { cells[0]=99; ++revision; undoRevision=0; }
};
int main(int argc, char** argv) {
    if(argc!=2) { std::cerr << "usage: onnx_inference linear.onnx\n"; return 2; }
    try {
        Ort::Env env(ORT_LOGGING_LEVEL_WARNING,"learning");
        Ort::SessionOptions options; options.SetIntraOpNumThreads(1);
        Ort::Session session(env,argv[1],options);
        auto inputType=session.GetInputTypeInfo(0); // Parent owns the borrowed shape view.
        auto info=inputType.GetTensorTypeAndShapeInfo();
        assert(info.GetElementType()==ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT);
        assert((info.GetShape()==std::vector<int64_t>{1,3}));
        auto launch = [&](int generation, int revision) {
            // Session/env remain alive until all futures finish. Each worker owns its input.
            return std::async(std::launch::async,[&session,generation,revision] {
                std::array<float,3> input{1,2,3}; std::array<int64_t,2> shape{1,3};
                auto memory=Ort::MemoryInfo::CreateCpu(OrtArenaAllocator,OrtMemTypeDefault);
                auto tensor=Ort::Value::CreateTensor<float>(memory,input.data(),input.size(),shape.data(),shape.size());
                const char* names[]={"x"}; const char* outputs[]={"y"};
                auto result=session.Run(Ort::RunOptions{nullptr},names,&tensor,1,outputs,1);
                assert(result.size()==1 && result[0].IsTensor());
                assert(result[0].GetTensorTypeAndShapeInfo().GetElementCount()==3);
                const float* data=result[0].GetTensorData<float>();
                return Proposal{generation,revision,std::vector<float>(data,data+3)}; // Copy before result dies.
            });
        };
        Document document;
        auto pending=launch(1,document.revision);
        const auto proposed=pending.get(); // A CLI test waits; a UI dispatches completion off its event thread.
        for(int i=0;i<3;++i) assert(std::fabs(proposed.values[i]-(3+2*i))<1e-6f);
        assert(!document.apply(proposed,2)); // Cancelled/replaced generation.
        document.remoteEdit();
        assert(!document.apply(proposed,1) && document.cells[0]==99); // Stale document.
        auto retry=launch(2,document.revision);
        assert(document.apply(retry.get(),2));
        assert((document.cells==std::array<float,3>{3,5,7}));
        assert(document.undo() && document.cells[0]==99); // Restore the state before our own transaction.
        assert(!document.undo());
        std::cout << "PASS: ORT C++ CPU [3,5,7], async ownership, cancel/stale rejection, commit and Undo\n";
    } catch(const Ort::Exception& e) { std::cerr << e.what() << '\n'; return 1; }
}
