//----------------------------------------------------------------------------
//
// \brief   Main test file
//
//----------------------------------------------------------------------------


//---Includes-----------------------------------------------------------------


#if defined ( CATCH_V3 )
   #include <catch2/catch_test_macros.hpp>
#elif defined ( CATCH_V2 )
   #include <catch2/catch.hpp>
#elif defined ( CATCH_V1 )
   #include <catch/catch.hpp>
#else
   #error "Either 'catch' or 'catch2' has to be installed"
#endif

#include <QApplication>
#include <biwak/linux/boardgui.h>
#include <biwak/output_blink_modes.h>
#include <biwak/heartbeat.hpp>
#include <lepto/imago.hpp>


//---Implementation-----------------------------------------------------------


TEST_CASE( "Heartbeat", "[default]" )
{
   int argc=1;
   char* argv[1]{ (char*)"test_heartbeat" };

   QString s=qgetenv("DISPLAY");
   if( s.isEmpty() )
   {
      qputenv("QT_QPA_PLATFORM", "offscreen");
   }

   QApplication app( argc, argv, false );
   CBoardGui boardGui;
   
   boardGui.show();

   CLed led(eGpioPeripheralA, eGpioPin0);
   CHeartBeat heartBeat(led);

   auto eventLoop = [&app, &boardGui] ( void )
   {
      biwakEventLoop();
      app.processEvents();
      // Just in case something spams logs
      usleep(1000);
      return;
   };

   CImago<typeof(eventLoop)> imago( eventLoop );

   #if ! IS_ENABLED( CONFIG_BIWAK_LOG_HEARTBEAT )
      #error BIWAK_LOG_HEARTBEAT is not set. I want to test this.
   #endif
   
   #if ! IS_ENABLED( CONFIG_BIWAK_LOG )
      #error BIWAK_LOG, is not set. I want to test this.
   #endif

   SECTION( "Normal" )
   {
      // Correct logging implementation
      REQUIRE ( lLogInfo() == BIWAK_CODE );

      // Previous tests might have set an error alreday
      eventLoop();
      logHeartBeat( ELogCategory::Calm | 0 );
      eventLoop();

      // Normal state: double-blink
      REQUIRE ( led.getBlinkMode() == BlinkModes::_double );

      // Does not go off
      eventLoop();
      REQUIRE ( led.getBlinkMode() == BlinkModes::_double );
   } // SECTION

   SECTION( "Warning" )
   {
      lWarning("This is a warning");
      eventLoop();

      // Warning state: leafe double-blink
      INFO( "Blink mode should not stay at _double after warning" );
      REQUIRE_FALSE ( led.getBlinkMode() == BlinkModes::_double );

      // Warning state: go error
      INFO( "Blink mode should be error-blinking" );
      REQUIRE ( led.getBlinkMode() == BlinkModes::error );

      // Require warning to go away
      imago.waitTime( HEARTBEAT_WARNING_DURATION_SECONDS + 2 );
      INFO( "Blink mode should go back to normal blinking" );
      REQUIRE ( led.getBlinkMode() == BlinkModes::_double );
   } // SECTION

   SECTION( "Critical" )
   {
      lCritical("This is a Error");
      eventLoop();
      
      // Warning state: go error
      INFO( "Blink mode must not stay calm after critical error" );
      REQUIRE_FALSE( led.getBlinkMode() == BlinkModes::_double );
      
      // Warning state: go error
      INFO( "Blink mode should go fatal" );
      REQUIRE ( led.getBlinkMode() == BlinkModes::blink );

      // Require error NOT to go away by time
      imago.waitTime( HEARTBEAT_WARNING_DURATION_SECONDS + 1 );
      REQUIRE ( led.getBlinkMode() == BlinkModes::blink );

      // Require error NOT to go away by warning
      lWarning("This is a warning");
      eventLoop();
      REQUIRE ( led.getBlinkMode() == BlinkModes::blink );
   }

   SECTION( "Calm" )
   {
      lCritical("This is a Error");
      eventLoop();

      // Just go error
      INFO( "Blink mode should go fatal" );
      REQUIRE ( led.getBlinkMode() == BlinkModes::blink );

      // Require error go away by calming
      logHeartBeat( ELogCategory::Calm | 0 );
      REQUIRE ( led.getBlinkMode() == BlinkModes::_double );
   }

   SECTION( "Beackon" )
   {
      REQUIRE ( led.getBlinkMode() == BlinkModes::_double );

      logHeartBeat( ELogCategory::Beckon | 0 );
      INFO( "Blink mode should go beckon" );
      REQUIRE ( led.getBlinkMode() == BlinkModes::triple );

      // Require beckon to go away by time
      imago.waitTime( HEARTBEAT_BECKON_DURATION_SECONDS + 1 );
      REQUIRE ( led.getBlinkMode() == BlinkModes::_double );
   }

   SECTION( "Beackon on warning" )
   {
      lWarning("This is a warning");
      eventLoop();
      REQUIRE ( led.getBlinkMode() == BlinkModes::error );

      logHeartBeat( ELogCategory::Beckon | 0 );
      INFO( "Blink mode 'error' should not go beckon" );
      REQUIRE ( led.getBlinkMode() == BlinkModes::error );
   }

}; // TEST_CASE


//---fin----------------------------------------------------------------------
