#pragma once

#include <QObject>
#include <QScopedPointer>

#include "QGCMapPolygon.h"
#include "QmlObjectListModel.h"

#include "Geometry/WimaCorridorData.h"
#include "Geometry/WimaMeasurementAreaData.h"
#include "Geometry/WimaServiceAreaData.h"

#include "SettingsFact.h"

#include "Geometry/GeoPoint3D.h"
#include "RoutingThread.h"
#include "Snake/NemoInterface.h"

#include "WaypointManager/EmptyManager.h"
#include "WaypointManager/RTLManager.h"

#include "utilities.h"

#include <map>

typedef std::unique_ptr<rapidjson::Document> JsonDocUPtr;

class WimaController : public QObject {
  Q_OBJECT
public:
  WimaController(QObject *parent = nullptr);

  // Controllers.
  Q_PROPERTY(PlanMasterController *masterController READ masterController WRITE
                 setMasterController NOTIFY masterControllerChanged)
  Q_PROPERTY(MissionController *missionController READ missionController WRITE
                 setMissionController NOTIFY missionControllerChanged)
  // Wima Data.
  Q_PROPERTY(QmlObjectListModel *visualItems READ visualItems NOTIFY
                 visualItemsChanged)
  Q_PROPERTY(QmlObjectListModel *missionItems READ missionItems NOTIFY
                 missionItemsChanged)
  Q_PROPERTY(
      QVariantList waypointPath READ waypointPath NOTIFY waypointPathChanged)
  Q_PROPERTY(Fact *enableWimaController READ enableWimaController CONSTANT)
  // Waypoint navigaton.
  Q_PROPERTY(Fact *flightSpeed READ flightSpeed CONSTANT)
  Q_PROPERTY(Fact *altitude READ altitude CONSTANT)

  // Controllers.
  PlanMasterController *masterController(void);
  MissionController *missionController(void);
  // Wima Data
  QmlObjectListModel *visualItems(void);
  QGCMapPolygon joinedArea(void) const;
  // Waypoints.
  QmlObjectListModel *missionItems(void);
  QVariantList waypointPath(void);
  // Settings facts.
  Fact *enableWimaController(void);
  Fact *flightSpeed(void);
  Fact *altitude(void);

  bool uploadOverrideRequired(void) const;
  bool vehicleHasLowBattery(void) const;

  // Property setters
  void setMasterController(PlanMasterController *masterController);
  void setMissionController(MissionController *missionController);

  // Member Methodes
  Q_INVOKABLE WimaController *thisPointer();
  // Smart RTL.
  Q_INVOKABLE void requestSmartRTL();
  Q_INVOKABLE void initSmartRTL();
  Q_INVOKABLE void executeSmartRTL();
  // Other.
  Q_INVOKABLE void removeVehicleTrajectoryHistory();
  Q_INVOKABLE bool upload();
  Q_INVOKABLE bool forceUpload();
  Q_INVOKABLE void removeFromVehicle();

  // static Members
  static const char *areaItemsName;
  static const char *missionItemsName;
  static const char *settingsGroup;
  static const char *enableWimaControllerName;
  static const char *flightSpeedName;
  static const char *altitudeName;

signals:
  // Controllers.
  void masterControllerChanged(void);
  void missionControllerChanged(void);
  // Wima data.
  void visualItemsChanged(void);
  // Waypoints.
  void missionItemsChanged(void);
  void waypointPathChanged(void);
  // Smart RTL.
  void smartRTLRequestConfirm(void);
  void smartRTLPathConfirm(void);
  // Upload.
  void forceUploadConfirm(void);

private slots:
  void planDataChangedHandler();
  void progressChangedHandler();
  bool _calcShortestPath(const QGeoCoordinate &start,
                         const QGeoCoordinate &destination,
                         QVector<QGeoCoordinate> &path);
  void _updateflightSpeed(void);
  void _updateAltitude(void);
  // SMART RTL
  void _checkBatteryLevel(void);
  bool _SRTLPrecondition(QString &errorString);
  void _initSmartRTL();
  void _smartRTLCleanUp(bool flying);
  // Snake.
  void _switchWaypointManager(WaypointManager::ManagerBase &manager);
  // Periodic tasks.
  void _eventTimerHandler(void);

private:
  // Controllers.
  PlanMasterController *_masterController;
  MissionController *_missionController;

  // Wima Data.
  QmlObjectListModel _areas; // contains all visible areas
  // joined area fromed by opArea, serArea, _corridor
  WimaJoinedAreaData _joinedArea;
  WimaMeasurementAreaData _measurementArea; // measurement area
  WimaServiceAreaData _serviceArea;         // area for supplying
  WimaCorridorData _corridor; // corridor connecting opArea and serArea
  bool _planDataValid;

  // Waypoint Managers.
  WaypointManager::AreaInterface _areaInterface;
  WaypointManager::Settings _WMSettings; // Waypoint Manager Settings
  WaypointManager::EmptyManager _emptyWM;
  WaypointManager::RTLManager _rtlWM;
  WaypointManager::ManagerBase *_currentWM;
  using ManagerList = QList<WaypointManager::ManagerBase *>;
  ManagerList _WMList;

  // Settings Facts.
  QMap<QString, FactMetaData *> _metaDataMap;
  SettingsFact _enableWimaController; // enables or disables the wimaControler
  // determines the number of overlapping waypoints between two consecutive
  // mission phases
  SettingsFact _flightSpeed; // mission flight speed
  SettingsFact _altitude;    // mission altitude

  // Smart RTL.
  QTimer _smartRTLTimer;
  bool _lowBatteryHandlingTriggered;

  // Periodic tasks.
  QTimer _eventTimer;
  EventTicker _batteryLevelTicker;
};
