#include "gui/dnd_loot_2.hpp"
#include "gui/guecstra.hpp"
#include "gui/uisystems.hpp"
#include <guecs/ui.hpp>
#include <fmt/core.h>
#include "dbc.hpp"

#define _log(M, F) {$cur_state = F; fmt::println("| {}:{} action={}, fcurs={}", __FILE_NAME__, __LINE__, #M, F);}


%%{
  machine DNDLoot;
  alphtype int;

  import "gui/fsm_events.hpp";

  action error {
    $cur_state = fcurs;
    fmt::println("!!! ERROR fcurs={}", fcurs);
  }

  action started {
    _log(started, fcurs);
    fbreak;
  }

  action loot_close {
    _log(loot_close, fcurs);
    $loot_ui.active = false;
    fbreak;
  }

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

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

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

    fbreak;
  }

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

    fbreak;
  }

  action at_end {
    _log(at_end, fcurs);
    fmt::println("> AT END");
    $grab_source = std::nullopt;
    $at_end = true;
    fbreak;
  }

  action not_end {
    _log(not_end, fcurs);
    fmt::println("% NOT_END");
    $at_end = false;
    fbreak;
  }

  action mouse_click {
    _log(mouse_click, fcurs);
    mouse_action(false);
    fbreak;
  }

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

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

main := start: (
  STARTED @started -> looting
),
looting: (
  LOOT_OPEN @loot_close -> looting |
  LOOT_ITEM @loot_grab -> loot_grab |
  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
) >at_end %not_end %err(error);
}%%

%% write data;

namespace gui {
  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)
  {
    %%write init;

    dbc::log("====================================");
    event(Event::STARTED);
    dbc::log("---------------- END CONSTRICT ------");
  }

  bool DNDLoot2::event(Event event, std::any data) {
    if(event == Event::TICK) return true;

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

    dbc::log(fmt::format(">>>> DND EVENT {}, state={}, cs={}, end={}",
          int(event), $cur_state, cs, $at_end));

    %%write exec noend;

    dbc::log(fmt::format("<<<< DND EVENT {}, state={}, cs={}, end={}",
          int(event), $cur_state, cs, $at_end));
    return $at_end;
  }
}
