#>cpp
#pragma once

#include <experimental/optional>
#include <unordered_map>

#include "communication/rpc/messages.hpp"
#include "distributed/coordination_rpc_messages.capnp.h"
#include "durability/distributed/recovery.hpp"
#include "durability/distributed/serialization.hpp"
#include "io/network/endpoint.hpp"
#include "io/network/serialization.hpp"
cpp<#

(lcp:namespace distributed)

(lcp:capnp-namespace "distributed")

(lcp:capnp-import 'dur "/durability/distributed/serialization.capnp")
(lcp:capnp-import 'io "/io/network/endpoint.capnp")
(lcp:capnp-import 'utils "/rpc/serialization.capnp")

(lcp:define-rpc register-worker
    (:request
     ((desired-worker-id :int16_t)
      (port :uint16_t)
      (durability-directory "std::string")))
  (:response
   ((registration-successful :bool)
    (durability-error :bool)
    (snapshot-to-recover "std::experimental::optional<std::pair<int64_t, tx::TransactionId>>"
                         :capnp-type "Utils.Optional(Utils.Pair(Utils.BoxUInt64, Utils.BoxUInt64))"
                         :capnp-save
                         (lambda (builder member capnp-name)
                           (declare (ignore capnp-name))
                           #>cpp
                           utils::SaveOptional<utils::capnp::Pair<utils::capnp::BoxUInt64, utils::capnp::BoxUInt64>, std::pair<int64_t, tx::TransactionId>>(
                               ${member}, &${builder},
                               [](auto builder, const auto &v) {
                                  auto first_builder = builder->initFirst();
                                  auto second_builder = builder->initSecond();
                                  first_builder.setValue(v.first);
                                  second_builder.setValue(v.second);
                               });
                           cpp<#)
                         :capnp-load
                         (lambda (reader member capnp-name)
                           (declare (ignore capnp-name))
                           #>cpp
                           ${member} = utils::LoadOptional<utils::capnp::Pair<utils::capnp::BoxUInt64, utils::capnp::BoxUInt64>, std::pair<int64_t, tx::TransactionId>>(
                               ${reader}, [](auto reader){
                                  return std::make_pair(reader.getFirst().getValue(), reader.getSecond().getValue());
                               });
                           cpp<#))
    (workers "std::unordered_map<int, io::network::Endpoint>"
             :capnp-type "Utils.Map(Utils.BoxInt16, Io.Endpoint)"
             :capnp-save
             (lambda (builder member capnp-name)
               (declare (ignore capnp-name))
               #>cpp
               utils::SaveMap<utils::capnp::BoxInt16, io::network::capnp::Endpoint>(
                   ${member}, &${builder}, [](auto *builder, const auto &entry) {
                     auto key_builder = builder->initKey();
                     key_builder.setValue(entry.first);
                     auto value_builder = builder->initValue();
                     Save(entry.second, &value_builder);
                   });
               cpp<#)
             :capnp-load
             (lambda (reader member capnp-name)
               (declare (ignore capnp-name))
               #>cpp
               utils::LoadMap<utils::capnp::BoxInt16, io::network::capnp::Endpoint>(&${member}, ${reader},
                              [](const auto &reader) {
                                  io::network::Endpoint value;
                                  Load(&value, reader.getValue());
                                  return std::make_pair(
                                      reader.getKey().getValue(), value);
                              });
               cpp<#)))))

(lcp:define-rpc cluster-discovery
    (:request
     ((worker-id :int16_t)
      (endpoint "io::network::Endpoint" :capnp-type "Io.Endpoint")))
  (:response ()))

(lcp:define-rpc stop-worker
    (:request ())
  (:response ()))

(lcp:define-rpc notify-worker-recovered
    (:request
     ((worker-id :int16_t)
      (recovery-info "std::experimental::optional<durability::RecoveryInfo>"
                     :capnp-type "Utils.Optional(Dur.RecoveryInfo)")))
  (:response ()))

(lcp:define-rpc heartbeat
    (:request ())
  (:response ()))

(lcp:pop-namespace) ;; distributed
