#include <catch2/catch_test_macros.hpp>
#include <iostream>
#include "rituals.hpp"
#include "fsm.hpp"
#include "dinkyecs.hpp"
#include "levelmanager.hpp"
#include "ai_debug.hpp"

TEST_CASE("ritual::Engine basic tests", "[rituals]") {
  ritual::Engine re("assets/rituals.json");
  auto craft_state = re.start();

  re.set_state(craft_state, "has_spikes", true);
  re.plan(craft_state);

  fmt::println("\n\n------------ TEST WILL DO PIERCE");
  craft_state.dump();
  REQUIRE(craft_state.will_do("pierce_type"));

  REQUIRE(craft_state.start != craft_state.original);
  craft_state.reset();
  REQUIRE(craft_state.start == craft_state.original);

  re.set_state(craft_state, "has_magick", true);
  re.set_state(craft_state, "has_spikes", true);
  re.plan(craft_state);

  fmt::println("\n\n------------ TEST WILL DO MAGICK TOO");
  craft_state.dump();
  REQUIRE(craft_state.will_do("pierce_type"));

  craft_state.pop();
  REQUIRE(craft_state.will_do("magick_type"));

  craft_state.reset();
  re.set_state(craft_state, "has_magick", true);
  re.set_state(craft_state, "has_spikes", true);
  re.set_state(craft_state, "shiny_bauble", true);
  re.plan(craft_state);

  REQUIRE(craft_state.is_combined());
  fmt::println("\n\n------------ TEST WILL DO DAMAGE BOOST");
  craft_state.dump();

  craft_state.reset();
  re.set_state(craft_state, "has_magick", true);
  re.set_state(craft_state, "cursed_item", true);
  re.set_state(craft_state, "shiny_bauble", true);
  re.plan(craft_state);
  REQUIRE(craft_state.is_combined());

  fmt::println("\n\n------------ TEST WILL DO LARGE DAMAGE BOOST");
  craft_state.dump();
}

TEST_CASE("craft_state can be finalized for the end result", "[rituals]") {
  ritual::Engine re("assets/rituals.json");
  auto craft_state = re.start();

  re.set_state(craft_state, "has_magick", true);
  re.set_state(craft_state, "cursed_item", true);
  re.set_state(craft_state, "shiny_bauble", true);
  re.plan(craft_state);
  REQUIRE(craft_state.is_combined());

  fmt::println("\n\n------------ CYCLES AVOIDED");
  craft_state.dump();

  auto ritual = re.finalize(craft_state);
  ritual.dump();
}


TEST_CASE("the ritual belt works", "[rituals]") {
  ritual::Belt the_belt;
  ritual::Engine re;
  auto craft_state = re.start();

  re.set_state(craft_state, "has_magick", true);
  re.plan(craft_state);
  REQUIRE(craft_state.is_combined());
  craft_state.dump();

  {
    auto ritual = re.finalize(craft_state);
    the_belt.equip(0, ritual);
    REQUIRE(the_belt.has(0));
  }

  {
    auto ritual = the_belt.get(0);
    ritual.dump();
  }

  {
    the_belt.unequip(0);
    REQUIRE(!the_belt.has(0));
  }

  craft_state.reset();
  REQUIRE(craft_state.plan.script.size() == 0);
  REQUIRE(!craft_state.plan.complete);
  REQUIRE(craft_state.start == craft_state.original);
  REQUIRE(!craft_state.is_combined());
}

TEST_CASE("ritual blanket basic operations", "[rituals-blanket]") {
  ritual::Blanket blanket;

  DinkyECS::Entity other = blanket.add("rusty_nails");
  DinkyECS::Entity ent = blanket.add("severed_finger");
  auto& name = blanket.get(ent);
  REQUIRE(name == "severed_finger");

  REQUIRE(blanket.has(ent));
  blanket.remove(ent);
  REQUIRE(!blanket.has(ent));
  REQUIRE(blanket.has(other));

  REQUIRE(!blanket.is_selected(ent));
  REQUIRE(!blanket.is_selected(other));
  blanket.select(ent);
  REQUIRE(blanket.is_selected(ent));
  REQUIRE(!blanket.is_selected(other));

  blanket.deselect(ent);
  REQUIRE(!blanket.is_selected(ent));

  blanket.select(ent);
  blanket.select(other);
  REQUIRE(blanket.is_selected(ent));
  REQUIRE(blanket.is_selected(other));

  blanket.reset();
  REQUIRE(!blanket.is_selected(ent));
  REQUIRE(!blanket.is_selected(other));
  REQUIRE(blanket.selected.empty());
  REQUIRE(blanket.selected.size() == 0);
}