#ifndef MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_
#define MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_

#include <devices/powerSwitcherList.h>
#include <fsfw/action/HasActionsIF.h>
#include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/power/PowerSwitchIF.h>
#include <fsfw/returnvalues/returnvalue.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/timemanager/Countdown.h>
#include <fsfw_hal/common/gpio/GpioIF.h>

#include <unordered_map>

#include "events/subsystemIdRanges.h"
#include "returnvalues/classIds.h"

/**
 * @brief	This class is used to control the solar array deployment.
 *
 * @author	J. Meier
 */
class SolarArrayDeploymentHandler : public ExecutableObjectIF,
                                    public SystemObject,
                                    public HasActionsIF {
 public:
  static const DeviceCommandId_t DEPLOY_SOLAR_ARRAYS = 0x5;

  /**
   * @brief constructor
   *
   * @param setObjectId   The object id of the SolarArrayDeploymentHandler.
   * @param gpioDriverId  The id of the gpio com if.
   * @param gpioCookie    GpioCookie holding information about the gpios used to switch the
   *                      transistors.
   * @param mainLineSwitcherObjectId  The object id of the object responsible for switching
   *                                  the 8V power source. This is normally the PCDU.
   * @param mainLineSwitch    The id of the main line switch. This is defined in
   *                          powerSwitcherList.h.
   * @param deplSA1   gpioId of the GPIO controlling the deployment 1 transistor.
   * @param deplSA2   gpioId of the GPIO controlling the deployment 2 transistor.
   * @param burnTimeMs  Time duration the power will be applied to the burn wires.
   */
  SolarArrayDeploymentHandler(object_id_t setObjectId, object_id_t gpioDriverId,
                              CookieIF* gpioCookie, object_id_t mainLineSwitcherObjectId,
                              pcdu::Switches mainLineSwitch, gpioId_t deplSA1, gpioId_t deplSA2,
                              uint32_t burnTimeMs);

  virtual ~SolarArrayDeploymentHandler();

  virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;

  virtual MessageQueueId_t getCommandQueue() const override;
  virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
                                      const uint8_t* data, size_t size) override;
  virtual ReturnValue_t initialize() override;

 private:
  static const uint8_t INTERFACE_ID = CLASS_ID::SA_DEPL_HANDLER;
  static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0);
  static const ReturnValue_t DEPLOYMENT_ALREADY_EXECUTING = MAKE_RETURN_CODE(0xA1);
  static const ReturnValue_t MAIN_SWITCH_TIMEOUT_FAILURE = MAKE_RETURN_CODE(0xA2);
  static const ReturnValue_t SWITCHING_DEPL_SA1_FAILED = MAKE_RETURN_CODE(0xA3);
  static const ReturnValue_t SWITCHING_DEPL_SA2_FAILED = MAKE_RETURN_CODE(0xA4);

  static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SA_DEPL_HANDLER;
  static const Event MAIN_SWITCH_ON_TIMEOUT = MAKE_EVENT(0, severity::LOW);
  static const Event MAIN_SWITCH_OFF_TIMEOUT = MAKE_EVENT(1, severity::LOW);
  static const Event DEPLOYMENT_FAILED = MAKE_EVENT(2, severity::HIGH);
  static const Event DEPL_SA1_GPIO_SWTICH_ON_FAILED = MAKE_EVENT(3, severity::HIGH);
  static const Event DEPL_SA2_GPIO_SWTICH_ON_FAILED = MAKE_EVENT(4, severity::HIGH);

  enum StateMachine {
    WAIT_ON_DELOYMENT_COMMAND,
    SWITCH_8V_ON,
    WAIT_ON_8V_SWITCH,
    SWITCH_DEPL_GPIOS,
    WAIT_ON_DEPLOYMENT_FINISH,
    WAIT_FOR_MAIN_SWITCH_OFF
  };

  StateMachine stateMachine = WAIT_ON_DELOYMENT_COMMAND;

  /**
   * This countdown is used to check if the PCDU sets the 8V line on in the intended time.
   */
  Countdown mainSwitchCountdown;

  /**
   * This countdown is used to wait for the burn wire being successful cut.
   */
  Countdown deploymentCountdown;

  /**
   * The message queue id of the component commanding an action will be stored in this variable.
   * This is necessary to send later the action finish replies.
   */
  MessageQueueId_t rememberCommanderId = 0;

  /** Size of command queue */
  size_t cmdQueueSize = 20;

  /** The object ID of the GPIO driver which switches the deployment transistors */
  object_id_t gpioDriverId;

  CookieIF* gpioCookie;

  /** Object id of the object responsible to switch the 8V power input. Typically the PCDU. */
  object_id_t mainLineSwitcherObjectId;

  /** Switch number of the 8V power switch */
  uint8_t mainLineSwitch;

  gpioId_t deplSA1;
  gpioId_t deplSA2;

  GpioIF* gpioInterface = nullptr;

  /** Time duration switches are active to cut the burn wire */
  uint32_t burnTimeMs;

  /** Queue to receive messages from other objects. */
  MessageQueueIF* commandQueue = nullptr;

  /**
   * After initialization this pointer will hold the reference to the main line switcher object.
   */
  PowerSwitchIF* mainLineSwitcher = nullptr;

  ActionHelper actionHelper;

  void readCommandQueue();

  /**
   * @brief   This function performs actions dependent on the current state.
   */
  void handleStateMachine();

  /**
   * @brief   This function polls the 8V switch state and changes the state machine when the
   *          switch has been enabled.
   */
  void performWaitOn8VActions();

  /**
   * @brief   This functions handles the switching of the solar array deployment transistors.
   */
  void switchDeploymentTransistors();

  /**
   * @brief   This function performs actions to finish the deployment. Essentially switches
   *          are turned of after the burn time has expired.
   */
  void handleDeploymentFinish();
};

#endif /* MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ */