#pragma once

#include "world/GameTown.h"
#include <frostbite2D/scene/scene.h>
#include <map>
#include <optional>

namespace frostbite2D {

class Actor;
class CharacterObject;
class GameDebugUIScene;
class GameMap;

class GameWorld : public Scene {
public:
  GameWorld();
  ~GameWorld() override = default;

  void onEnter() override;
  void onExit() override;
  void Update(float deltaTime) override;

  void AddCharacter(RefPtr<Actor> actor, int townId);
  void MoveCharacter(RefPtr<Actor> actor, int townId, int area);
  void RequestMoveCharacter(RefPtr<Actor> actor, int townId, int area);
  void UpdateMoveAreaSuppression(GameMap* map, size_t moveAreaIndex);
  bool ShouldSuppressMoveArea(GameMap* map, size_t moveAreaIndex) const;

  Actor* GetMainActor() const;
  CharacterObject* GetMainCharacter() const;
  GameTown* GetCurrentTown() const;
  GameMap* GetCurrentMap() const;

  static GameWorld* GetWorld();

private:
  struct PendingCharacterMove {
    RefPtr<Actor> actor;
    int townId = -1;
    int area = -1;
  };

  struct SuppressedMoveArea {
    GameMap* map = nullptr;
    size_t moveAreaIndex = GameMap::kInvalidMoveAreaIndex;
  };

  bool InitWorld();
  bool InitMainCharacter(int townId);
  void ProcessPendingCharacterMove();
  void EnsureDebugScene();
  void RefreshDebugContext();
  void SetSuppressedMoveArea(GameMap* map, size_t moveAreaIndex);
  void ClearSuppressedMoveArea();

  std::map<int, std::string> townPathMap_;
  std::map<int, RefPtr<GameTown>> townMap_;
  RefPtr<Actor> mainActor_;
  RefPtr<GameDebugUIScene> debugScene_;
  std::optional<PendingCharacterMove> pendingCharacterMove_;
  std::optional<SuppressedMoveArea> suppressedMoveArea_;
  int curTown_ = -1;
  bool initialized_ = false;
};

} // namespace frostbite2D
