#pragma once

#include "mission/position_resolver.hpp"

#include <nlohmann/json.hpp>

#include <atomic>
#include <mutex>
#include <optional>
#include <string>
#include <thread>

namespace lm {

class Database;
class IoModuleService;
class IoZoneRuntime;
class MapStore;
class MissionStore;
class PathService;
class TransitionStore;

class MissionQueue
{
public:
  MissionQueue(Database& db,
               MapStore& maps,
               TransitionStore& transitions,
               MissionStore& missions,
               IoModuleService& io_modules,
               IoZoneRuntime& io_zones,
               PathService& paths);
  ~MissionQueue();

  MissionQueue(const MissionQueue&) = delete;
  MissionQueue& operator=(const MissionQueue&) = delete;

  nlohmann::json list() const;
  nlohmann::json runnerStatus() const;

  std::optional<nlohmann::json> enqueue(const nlohmann::json& payload, std::string& err);
  bool removeById(const std::string& id, std::string& err);
  bool clearAll(std::string& err);
  bool reorder(const nlohmann::json& ordered_ids, std::string& err);
  bool pause(std::string& err);
  bool resume(std::string& err);
  bool cancel(std::string& err);

private:
  enum class LoopControl { None, Break, Continue };

  Database& db_;
  MapStore& maps_;
  TransitionStore& transitions_;
  MissionStore& missions_;
  IoModuleService& io_modules_;
  IoZoneRuntime& io_zones_;
  PathService& paths_;
  PositionResolver position_resolver_;
  mutable std::recursive_mutex mu_;
  nlohmann::json queue_;
  nlohmann::json runner_;

  std::thread worker_;
  std::atomic<bool> stop_{false};
  std::atomic<bool> wake_{false};
  std::atomic<bool> paused_{false};
  std::atomic<bool> cancel_{false};

  void load();
  void saveUnlocked() const;
  void ensureRunnerDefaults();
  void startWorkerIfNeeded();
  void workerLoop();
  void runMissionActions(nlohmann::json& entry);
  LoopControl executeActionsUnlocked(const nlohmann::json& actions,
                                     const nlohmann::json& parameters,
                                     nlohmann::json& log,
                                     int loop_depth,
                                     bool allow_auto_transition = true);
  void runAutoTransitionIfNeeded(const std::string& from_map_id,
                                 const std::string& to_map_id,
                                 const nlohmann::json& parameters,
                                 nlohmann::json& log,
                                 int loop_depth);
  void sleepMs(int ms);
  void setRunnerState(const std::string& state, const std::string& message = "");
  void completeMoveToPosition(const ResolvedPosition& resolved, const std::string& label, nlohmann::json& log);
  void insertByPriorityUnlocked(nlohmann::json& entry);
};

}  // namespace lm
