#pragma once

#include <functional>
#include "game/components.hpp"

namespace System {
  using MovingFunc = std::function<void(components::Position& move_to)>;
  using CombatFunc = std::function<void(int attack_id)>;
  using RenderFunc = std::function<void()>;
  using UpdateFunc = std::function<void()>;
  using UseItemFunc = std::function<void(const std::string& slot_name)>;
  using PickupFunc = std::function<void()>;

  struct Registry {
    std::vector<MovingFunc> $moving;
    std::vector<CombatFunc> $combat;
    std::vector<RenderFunc> $render;
    std::vector<UpdateFunc> $update;
    std::vector<UseItemFunc> $use_item;
    std::vector<PickupFunc> $pickup;

    void addMoving(MovingFunc action) {
      $moving.emplace_back(action);
    }

    void addCombat(CombatFunc action) {
      $combat.emplace_back(action);
    }

    void addRender(RenderFunc action) {
      $render.emplace_back(action);
    }

    void addUpdate(UpdateFunc action) {
      $update.emplace_back(action);
    }

    void addUseItem(UseItemFunc action) {
      $use_item.emplace_back(action);
    }

    void addPickup(PickupFunc action) {
      $pickup.emplace_back(action);
    }

    void runMoving(components::Position move_to) {
      for(auto func : $moving) {
        func(move_to);
      }
    }

    void runCombat(int attack_id) {
      for(auto func : $combat) {
        func(attack_id);
      }
    }

    void runRender() {
      for(auto func : $render) {
        func();
      }
    }

    void runUpdate() {
      for(auto func : $update) {
        func();
      }
    }

    void runUseItem(const std::string& slot_name) {
      for(auto func : $use_item) {
        func(slot_name);
      }
    }

    void runPickup() {
      for(auto func : $pickup) {
        func();
      }
    }
  };
}
