// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 Ivan Baidakou

#if defined(__ANDROID__)
#undef __ANDROID__
#endif

#include "catch.hpp"

#include "rotor-light/planner.hpp"
#include "rotor-light/queue.hpp"
#include "rotor-light/supervisor.hpp"

using namespace rotor_light;

struct Ping : Message {
  static constexpr auto type_id = __LINE__;
  using Message::Message;
};

struct Pong : Message {
  static constexpr auto type_id = __LINE__;
  using Message::Message;
};

using MessageStorage =
    traits::MessageStorage<message::ChangeState, message::ChangeStateAck, Ping,
                           Pong>;

struct Pinger : Actor<2> {
  using Parent = Actor<2>;

  void initialize() override {
    subscribe(&Pinger::on_pong);
    Parent::initialize();
  }

  void on_pong(Pong &) {
    ok = true;
    supervisor->stop();
  }

  void advance_start() override {
    Parent::advance_start();
    send<ctx::thread, Ping>(0, ponger_id);
  }

  bool ok = false;
  ActorId ponger_id;
};

struct Ponger : Actor<2> {
  using Parent = Actor<2>;

  void initialize() override {
    subscribe(&Ponger::on_ping);
    Parent::initialize();
  }

  void on_ping(Ping &) {
    send<ctx::thread, Pong>(0, pinger_id);
    ok = true;
  }

  void advance_start() override { Parent::advance_start(); }

  bool ok = false;
  ActorId pinger_id;
};

using AppQueue = Queue<MessageStorage, 5>;
using AppSupervisor = Supervisor<3, Pinger, Ponger>;
using AppPlanner = Planner<1>;

TEST_CASE("simple ping-pong example", "[actor]") {
  AppQueue queue;
  AppPlanner planner;
  Context context{&queue, &planner, nullptr};
  AppSupervisor sup;
  sup.bind(context);
  auto pinger = sup.get_child<0>();
  auto ponger = sup.get_child<1>();
  pinger->ponger_id = ponger->get_id();
  ponger->pinger_id = pinger->get_id();

  sup.start();
  sup.process();

  CHECK(pinger->ok);
  CHECK(ponger->ok);

  CHECK(sup.get_state() == State::off);
  CHECK(pinger->get_state() == State::off);
  CHECK(ponger->get_state() == State::off);
}
