#include <iostream>
#include "gui/dnd_events.hpp"
#include <any>
#include "gui/guecstra.hpp"
#include "gui/uisystems.hpp"
#include <guecs/ui.hpp>
#include "gui/status_ui.hpp"
#include "gui/loot_ui.hpp"
#include "gui/event_router.hpp"


%%{
  machine DNDLoot;
  alphtype int;

  import "../gui/dnd_events.hpp";

  action loot_close {
    $loot_ui.active = false;
  }

  action loot_grab {
    // NOTE: when grab_source could work to do the if that was here
    $grab_source = UISystem::loot_grab($loot_ui.$gui, data);
  }

  action inv_grab {
    $grab_source = UISystem::loot_grab($status_ui.$gui, data);
  }

  action loot_drop {
    if(UISystem::loot_drop($status_ui.$gui,
          $loot_ui.$gui, $grab_source, data))
    {
      fnext looting;
    }
  }

  action inv_drop {
    if(UISystem::loot_drop($loot_ui.$gui,
          $status_ui.$gui, $grab_source, data))
    {
      fnext looting;
    }
  }

  action end {
    $grab_source = std::nullopt;
  }

  action mouse_click {
    mouse_action(false);
  }

  action mouse_move {
    if($grab_source) {
      auto& source = $loot_ui.$gui.get<guecs::GrabSource>(*$grab_source);
      source.move($window.mapPixelToCoords($router.position));
    }
    mouse_action(true);
  }

mouse_click = (MOUSE_DRAG_START | MOUSE_CLICK | MOUSE_DROP);
mouse_move = (MOUSE_MOVE | MOUSE_DRAG);

main :=
start: (
  STARTED -> looting
),
looting: (
  LOOT_OPEN @loot_close -> looting |
  LOOT_SELECT @loot_grab -> loot_grab |
  INV_SELECT @inv_grab -> inv_grab |
  mouse_click @mouse_click -> looting |
  mouse_move @mouse_move -> looting
),
loot_grab: (
  LOOT_OPEN @loot_grab -> end |
  LOOT_SELECT @loot_grab -> looting |
  INV_SELECT @inv_drop -> looting |
  mouse_click @mouse_click -> loot_grab |
  mouse_move @mouse_move -> loot_grab
),
inv_grab: (
  LOOT_OPEN @loot_close -> end |
  LOOT_SELECT @loot_drop -> looting |
  INV_SELECT @inv_grab -> looting |
  mouse_click @mouse_click -> inv_grab |
  mouse_move @mouse_move -> inv_grab
),
end: (
  LOOT_ITEM @loot_grab -> loot_grab |
  LOOT_OPEN -> looting
);
}%%

%% write data;

namespace gui {

  class DNDLoot2 {
    public:
      std::optional<guecs::Entity> $grab_source = std::nullopt;
      StatusUI& $status_ui;
      LootUI& $loot_ui;
      sf::RenderWindow& $window;
      routing::Router& $router;

      DNDLoot2(StatusUI& status_ui,
          LootUI& loot_ui, sf::RenderWindow& window,
          routing::Router& router);

      bool event(DNDEvent ev, std::any data={});
      void mouse_action(bool hover);
      sf::Vector2f mouse_position();
  };

  sf::Vector2f DNDLoot2::mouse_position() {
    return $window.mapPixelToCoords($router.position);
  }

  void DNDLoot2::mouse_action(bool hover) {
    sf::Vector2f pos = mouse_position();
    $status_ui.mouse(pos.x, pos.y, hover);
    if($loot_ui.active) $loot_ui.mouse(pos.x, pos.y, hover);
  }

  DNDLoot2::DNDLoot2(StatusUI& status_ui, LootUI& loot_ui, sf::RenderWindow &window, routing::Router& router) :
    $status_ui(status_ui),
    $loot_ui(loot_ui),
    $window(window),
    $router(router)
  {
    event(DNDEvent::STARTED);
  }

  bool DNDLoot2::event(DNDEvent event, std::any data) {

    int cs = 0;
    int *p = (int *)&event;
    int *pe = p+1;

    %%write init;
    %%write exec;

    return false;
  }
}