#include "gui/status_ui.hpp"
#include "components.hpp"
#include "inventory.hpp"
#include <guecs/ui.hpp>
#include "rand.hpp"
#include <fmt/xchar.h>

namespace gui {
  using namespace guecs;
  using std::any, std::any_cast, std::string, std::make_any;

  StatusUI::StatusUI(GameLevel level) :
    $level(level), $ritual_ui(level)
  {
    $gui.position(STATUS_UI_X, STATUS_UI_Y, STATUS_UI_WIDTH, STATUS_UI_HEIGHT);
    $gui.layout(
        "[ ritual_ui ]"
        "[inv_1|inv_2|inv_3]"
        "[inv_4|*%(200,300)character_view|_|inv_5]"
        "[inv_6|_|_                        |inv_7]"
        "[inv_8|_|_                        |inv_9]"
        "[inv_10|inv_11|inv_12]");

    size_t inv_id = 0;
    for(auto [name, entity] : $gui.$name_ents) {
      if(name.starts_with("inv_")) {
        $slots[name] = inv_id++;
      }
    }
  }

  void StatusUI::init() {
    $gui.set<Background>($gui.MAIN, {$gui.$parser});

    for(auto& [name, cell] : $gui.cells()) {
      if(name == "character_view") {
        auto char_view = $gui.entity(name);
        $gui.set<Rectangle>(char_view, {});
        $gui.set<Sprite>(char_view, {"peasant_girl"});
      } else {
        auto button = $gui.entity(name);
        $gui.set<Rectangle>(button, {});
        $gui.set<ActionData>(button, {make_any<string>(name)});

        if(name == "ritual_ui") {
          $gui.set<Clickable>(button, {
              [this](auto, auto){ select_ritual(); }
          });
          $gui.set<Sound>(button, {"pickup"});
        } else {
          $gui.set<Textual>(button, {guecs::to_wstring(name)});
          $gui.set<Clickable>(button, {
              [this](auto ent, auto data){ select_slot(ent, data); }
          });
        }
      }
    }

    $ritual_ui.event(ritual::Event::STARTED);
    $gui.init();
  }

  bool StatusUI::mouse(float x, float y, bool hover) {
    if($ritual_ui.is_open()) {
      return $ritual_ui.mouse(x, y, hover);
    } else {
      return $gui.mouse(x, y, hover);
    }
  }

  void StatusUI::select_ritual() {
    $ritual_ui.event(ritual::Event::TOGGLE);
  }

  void StatusUI::select_slot(DinkyECS::Entity ent, any slot_name) {
    dbc::check(slot_name.has_value(), "passed select_slot an any without a value");

    auto cn = $gui.get<CellName>(ent);
    auto world = $level.world;

    if(world->has<components::Inventory>($level.player)) {
      auto& inventory = world->get<components::Inventory>($level.player);
      size_t inv_id = $slots[any_cast<string>(slot_name)];

      if(inventory.has_item(inv_id)) {
        auto [used, name] = inventory.use($level, inv_id);
      }
    }
  }

  /* WARNING: This is really not the greatest way to do this. */
  void StatusUI::update() {
    auto world = $level.world;
    if(world->has<components::Inventory>($level.player)) {
      auto& inventory = world->get<components::Inventory>($level.player);

      for(auto& [slot_name, inv_id] : $slots) {
        if(inventory.has_item(inv_id)) {
          auto slot = $gui.entity(slot_name);
          auto& item = inventory.get(inv_id);
          auto comp_sprite = components::get<components::Sprite>(item.data);
          $gui.set_init<guecs::Sprite>(slot, {comp_sprite.name});
          string count_label = fmt::format("{}", item.count);
          auto& label = $gui.get<Textual>(slot);
          label.text->setString(count_label);

          auto& sprite = $gui.get<guecs::Sprite>(slot);

          if(item.count == 0) {
            sprite.sprite->setColor({125, 125, 125});
          } else {
            sprite.sprite->setColor({255, 255, 255});
          }
        }
      }
    }
  }

  void StatusUI::render(sf::RenderWindow &window) {
    $gui.render(window);
    // $gui.debug_layout(window);
    $ritual_ui.render(window);
  }

  void StatusUI::update_level(GameLevel &level) {
    $level = level;
    init();
  }
}