#include <catch2/catch_test_macros.hpp>
#include <fmt/core.h>
#include <string>
#include "../fsm.hpp"

using namespace fmt;
using std::string;

enum class MyState {
  START, RUNNING, END
};

enum class MyEvent {
  STARTED, PUSH, QUIT
};

class MyFSM : public DeadSimpleFSM<MyState, MyEvent> {
public:
  void event(MyEvent ev, string data="") {
    switch($state) {
      FSM_STATE(MyState, START, ev);
      FSM_STATE(MyState, RUNNING, ev, data);
      FSM_STATE(MyState, END, ev);
    }
  }

  void START(MyEvent ev) {
    println("<<< START {}", (int)ev);
    state(MyState::RUNNING);
  }

  void RUNNING(MyEvent ev, string &data) {
    if(ev == MyEvent::QUIT) {
      println("<<< QUITTING {}", data);
      state(MyState::END);
    } else {
      println("<<< RUN: {}", data);
      state(MyState::RUNNING);
    }
  }

  void END(MyEvent ev) {
    println("<<< STOP {}", (int)ev);
    state(MyState::END);
  }
};

TEST_CASE("confirm fsm works with optional data", "[utils]") {
  MyFSM fsm;

  REQUIRE(fsm.in_state(MyState::START));

  fsm.event(MyEvent::STARTED);
  REQUIRE(fsm.in_state(MyState::RUNNING));

  fsm.event(MyEvent::PUSH);
  REQUIRE(fsm.in_state(MyState::RUNNING));

  fsm.event(MyEvent::PUSH);
  REQUIRE(fsm.in_state(MyState::RUNNING));

  fsm.event(MyEvent::PUSH);
  REQUIRE(fsm.in_state(MyState::RUNNING));

  fsm.event(MyEvent::QUIT, "DONE!");
  REQUIRE(fsm.in_state(MyState::END));
}