#pragma once
#include <vector>
#include "matrix.hpp"
#include <bitset>
#include <limits>
#include <optional>
#include <nlohmann/json.hpp>
#include "config.hpp"
#include "goap.hpp"

namespace ai {
  struct EntityAI {
    std::string script;
    ai::State start;
    ai::State goal;
    ai::ActionPlan plan;

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

    EntityAI() {};

    bool wants_to(std::string name);

    bool active();

    void set_state(std::string name, bool setting);
    bool get_state(std::string name);

    void update();

    void dump();
  };

  struct AIManager {
    AIProfile profile;
    std::unordered_map<std::string, Action> actions;
    std::unordered_map<std::string, State> states;
    std::unordered_map<std::string, std::vector<Action>> scripts;
  };

  /* This is really only used in test to load different fixtures. */
  void reset();
  void init(std::string config_path);

  Action config_action(AIProfile& profile, nlohmann::json& config);
  State config_state(AIProfile& profile, nlohmann::json& config);

  int state_id(std::string name);
  State load_state(std::string state_name);
  Action load_action(std::string action_name);
  std::vector<Action> load_script(std::string script_name);

  void set(State& state, std::string name, bool value=true);
  bool test(State state, std::string name);
  ActionPlan plan(std::string script_name, State start, State goal);

  /* Mostly used for debugging and validation. */
  AIProfile* profile();
  void check_valid_action(std::string name, std::string msg);
}