#pragma once
#include "goap.hpp"
#include "ai.hpp"
#include "config.hpp"

namespace ritual {
  using JunkItem = std::string;
  using Entity = unsigned long;

  struct JunkPile {
    std::vector<JunkItem> contents;
  };

  enum class Element {
    NONE=0, FIRE=1, LIGHTNING=2
  };

  enum class Kind {
    NONE=0, PHYSICAL=1, MAGICK=2
  };

  struct CraftingState {
    std::string script;
    ai::State start;
    ai::State original;
    ai::State goal;
    ai::ActionPlan plan;

    CraftingState(std::string script, ai::State start, ai::State goal) :
      script(script), start(start), original(start), goal(goal)
    {
    }

    CraftingState() {};

    bool will_do(std::string name);
    void dump();
    ai::Action pop();
    bool is_combined();
    void reset();
  };

  struct Action {
    float probability = 1.0f;
    int damage = 0;
    Kind kind{Kind::NONE};
    Element element{Element::NONE};
    std::vector<std::string> names;

    void dump();
  };

  struct Engine {
    Config $config;
    ai::AIProfile $profile;
    std::unordered_map<std::string, ai::Action> $actions;
    std::unordered_map<std::string, ai::State> $states;
    std::unordered_map<std::string, std::vector<ai::Action>> $scripts;

    Engine(std::string config_path="assets/rituals.json");

    ai::State load_state(std::string name);
    ai::Action load_action(std::string name);
    CraftingState start();
    void set_state(CraftingState& ritual, std::string name, bool setting);
    void plan(CraftingState& ritual);
    Action finalize(CraftingState& ritual);
    void load_junk(CraftingState& ritual, const JunkItem& item);
  };

  struct Belt {
    int next_slot = 0;
    int max_slots = 6;
    std::unordered_map<int, Action> equipped;

    Action& get(int index);
    void equip(int index, Action& action);
    bool has(int index);
    void unequip(int index);
    int next();
  };

  struct Blanket {
    size_t entity_counter = 0;
    std::unordered_map<Entity, JunkItem> contents;
    std::unordered_map<Entity, bool> selected;

    Entity add(JunkItem name);
    JunkItem& get(Entity ent);
    bool has(Entity ent);
    void remove(Entity ent);
    void select(Entity ent);
    void deselect(Entity ent);
    void reset();
    bool is_selected(Entity ent);
    bool no_selections();
    void consume_crafting();
  };
}
