#pragma once
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/common/include/exception.h>

#include <maps/libs/json/include/builder.h>
#include <maps/libs/json/include/value.h>
#include <maps/libs/json/include/value_repr.h>
#include <maps/libs/json/include/std.h>

#include <maps/libs/http/include/http.h>

namespace maps::mrc::nirvana {

namespace nirvana_state {

const std::string RUNNING = "running";
const std::string SUCCESS = "success";
const std::string FAILED  = "failed";

} // namespace nirvana_state

struct BlockPattern {
    std::string GUID;
    std::string code;
};

enum class ExecutionState { Running, Success, Failed };

class WorkflowInstance
{
public:
    WorkflowInstance(
        const std::string& _oauthToken,
        const std::string& _workflowId,
        const std::string& _workflowInstanceId = "",
        const std::string& _quotaID = "default",
        const std::string& _comment = "");

    std::string getWorkflowInstanceId() const;

    BlockPattern addDataBlock(const std::string& dataId);

    BlockPattern addOperationBlock(const std::string& operationId);

    void setBlockParameters(
        const BlockPattern& blockPattern,
        std::function<void(maps::json::ArrayBuilder)> blockParams);

    void connectDataBlockToOperations(
        const BlockPattern& dataBlockPattern,
        const std::vector<BlockPattern>& operationBlocksPattern,
        const std::string& operationInputName);

    void connectOperationBlocks(
        const std::vector<BlockPattern>& srcBlocksPattern,
        const std::string& srcOutputName,
        const std::vector<BlockPattern>& dstBlocksPattern,
        const std::string& dstInputName);

    std::string getBlockResultUrl(
        const BlockPattern& blockPattern,
        const std::string& outputName);

    bool validateWorkflow();

    bool startWorkflow();

    ExecutionState getExecutionState();
private:
    void createWorkflowInstance();
    maps::json::Value launchCommand(
        const std::string& commandName,
        std::function<void(maps::json::ObjectBuilder)> params);
private:
    std::string oauthToken;
    std::string workflowId;
    std::string workflowInstanceId;
    std::string quotaID;
    std::string comment;

    uint64_t commandCallID;

    maps::http::Client httpClient;
};

} // namespace maps::mrc::nirvana
