#include <bsp_q7s/callbacks/q7sGpioCallbacks.h>
#include <fsfw/health/HealthTableIF.h>
#include <fsfw/power/DummyPowerSwitcher.h>
#include <mission/devices/devicedefinitions/GomspaceDefinitions.h>
#include <mission/system/tree/system.h>

#include "OBSWConfig.h"
#include "bsp_q7s/core/CoreController.h"
#include "bsp_q7s/core/ObjectFactory.h"
#include "busConf.h"
#include "devConf.h"
#include "dummies/helpers.h"
#include "eive/objects.h"
#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h"
#include "linux/ObjectFactory.h"
#include "linux/callbacks/gpioCallbacks.h"
#include "mission/core/GenericFactory.h"
#include "mission/system/tree/comModeTree.h"

void ObjectFactory::produce(void* args) {
  ObjectFactory::setStatics();
  HealthTableIF* healthTable = nullptr;
  PusTmFunnel* pusFunnel = nullptr;
  CfdpTmFunnel* cfdpFunnel = nullptr;
  ObjectFactory::produceGenericObjects(&healthTable, &pusFunnel, &cfdpFunnel);

  LinuxLibgpioIF* gpioComIF = nullptr;
  SerialComIF* uartComIF = nullptr;
  SpiComIF* spiMainComIF = nullptr;
  I2cComIF* i2cComIF = nullptr;
  createCommunicationInterfaces(&gpioComIF, &uartComIF, &spiMainComIF, &i2cComIF);
  /* Adding gpios for chip select decoding to the gpioComIf */
  q7s::gpioCallbacks::initSpiCsDecoder(gpioComIF);
  gpioCallbacks::disableAllDecoder(gpioComIF);

  // Hardware is usually not connected to EM, so we need to create dummies which replace lower
  // level components.
  dummy::DummyCfg dummyCfg;
  dummyCfg.addCoreCtrlCfg = false;
#if OBSW_ADD_SYRLINKS == 1
  dummyCfg.addSyrlinksDummies = false;
#endif
#if OBSW_ADD_GOMSPACE_PCDU == 1
  dummyCfg.addPowerDummies = false;
#endif
#if OBSW_ADD_ACS_BOARD == 1
  dummyCfg.addAcsBoardDummies = false;
#endif

  PowerSwitchIF* pwrSwitcher = nullptr;
#if OBSW_ADD_GOMSPACE_PCDU == 0
  pwrSwitcher = new DummyPowerSwitcher(objects::PCDU_HANDLER, 18, 0);
#else
  createPcduComponents(gpioComIF, &pwrSwitcher);
#endif

  dummy::createDummies(dummyCfg, *pwrSwitcher, gpioComIF);

  new CoreController(objects::CORE_CONTROLLER);

  // Regular FM code, does not work for EM if the hardware is not connected
  // createPcduComponents(gpioComIF, &pwrSwitcher);
  // createPlPcduComponents(gpioComIF, spiMainComIF, pwrSwitcher);
  // createSyrlinksComponents(pwrSwitcher);
  // createSunSensorComponents(gpioComIF, spiMainComIF, pwrSwitcher, q7s::SPI_DEFAULT_DEV);
  // createRtdComponents(q7s::SPI_DEFAULT_DEV, gpioComIF, pwrSwitcher, spiMainComIF);
  // createTmpComponents();
  // createSolarArrayDeploymentComponents();
  // createPayloadComponents(gpioComIF);
  // createHeaterComponents(gpioComIF, pwrSwitcher, healthTable);

  // TODO: Careful! Switching this on somehow messes with the communication with the ProASIC
  //       and will cause xsc_boot_copy commands to always boot to 0 0
  // createRadSensorComponent(gpioComIF);

#if OBSW_ADD_ACS_BOARD == 1
  createAcsBoardComponents(gpioComIF, uartComIF, *pwrSwitcher);
#endif

#if OBSW_ADD_MGT == 1
  createImtqComponents(pwrSwitcher);
#endif

#if OBSW_ADD_SYRLINKS == 1
  createSyrlinksComponents(pwrSwitcher);
#endif /* OBSW_ADD_SYRLINKS == 1 */

#if OBSW_ADD_RW == 1
  createReactionWheelComponents(gpioComIF, pwrSwitcher);
#endif

#if OBSW_ADD_BPX_BATTERY_HANDLER == 1
  createBpxBatteryComponent();
#endif

#if OBSW_ADD_STAR_TRACKER == 1
  createStrComponents(pwrSwitcher);
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
#if OBSW_ADD_CCSDS_IP_CORES == 1
  CcsdsIpCoreHandler* ipCoreHandler = nullptr;
  createCcsdsComponents(gpioComIF, &ipCoreHandler);
#if OBSW_TM_TO_PTME == 1
  ObjectFactory::addTmtcIpCoresToFunnels(*ipCoreHandler, *pusFunnel, *cfdpFunnel);
#endif
#endif /* OBSW_ADD_CCSDS_IP_CORES == 1 */
  /* Test Task */
#if OBSW_ADD_TEST_CODE == 1
  createTestComponents(gpioComIF);
#endif /* OBSW_ADD_TEST_CODE == 1 */
#if OBSW_ADD_SCEX_DEVICE == 1
  createScexComponents(q7s::UART_SCEX_DEV, pwrSwitcher, *SdCardManager::instance(), false,
                       pcdu::Switches::PDU1_CH5_SOLAR_CELL_EXP_5V);
#endif
  createAcsController(true);
  HeaterHandler* heaterHandler = nullptr;
  ObjectFactory::createGenericHeaterComponents(*gpioComIF, *pwrSwitcher, heaterHandler);
  createThermalController(*heaterHandler);
  satsystem::init();
}