#ifndef HIT_POSITION_LIFECYCLE_MANAGER_MQH
#define HIT_POSITION_LIFECYCLE_MANAGER_MQH

#include <Trade/Trade.mqh>

// Ticket-based position lifecycle manager for hedging accounts.
class CHITPositionLifecycleManager
{
private:
   string m_symbol;
   ulong  m_magic;
   ulong  m_deviation_points;
   int    m_close_after_seconds;
   CTrade m_trade;

public:
   CHITPositionLifecycleManager()
   {
      m_symbol = _Symbol;
      m_magic = 0;
      m_deviation_points = 10;
      m_close_after_seconds = 0;
   }

   bool Init(const string symbol,
             const ulong magic,
             const ulong deviation_points,
             const int close_after_seconds)
   {
      m_symbol = symbol;
      m_magic = magic;
      m_deviation_points = deviation_points;
      m_close_after_seconds = close_after_seconds;

      if(m_symbol == "")
        {
         Print("HITPositionLifecycleManager init failed: symbol is empty.");
         return false;
        }

      ResetLastError();
      if(!SymbolSelect(m_symbol, true))
        {
         Print("HITPositionLifecycleManager init failed: symbol=", m_symbol,
               " err=", GetLastError());
         return false;
        }

      m_trade.SetExpertMagicNumber(m_magic);
      m_trade.SetDeviationInPoints((int)m_deviation_points);
      m_trade.SetTypeFillingBySymbol(m_symbol);

      return true;
   }

   void SetCloseAfterSeconds(const int close_after_seconds)
   {
      m_close_after_seconds = close_after_seconds;
   }

   int CountTargetPositions()
   {
      int count = 0;

      for(int i = PositionsTotal() - 1; i >= 0; --i)
        {
         const ulong ticket = PositionGetTicket(i);
         if(ticket == 0)
            continue;
         if(!PositionSelectByTicket(ticket))
            continue;
         if(!IsTargetSelectedPosition())
            continue;

         count++;
        }

      return count;
   }

   bool CloseExpiredPositions()
   {
      if(m_close_after_seconds <= 0)
         return false;

      bool result = false;
      const datetime current_time = TimeCurrent();

      for(int i = PositionsTotal() - 1; i >= 0; --i)
        {
         const ulong ticket = PositionGetTicket(i);
         if(ticket == 0)
            continue;

         ResetLastError();
         if(!PositionSelectByTicket(ticket))
           {
            Print("HITPositionLifecycleManager select failed: ticket=", ticket,
                  " err=", GetLastError());
            continue;
           }

         if(!IsTargetSelectedPosition())
            continue;

         const datetime entry_time = (datetime)PositionGetInteger(POSITION_TIME);
         if(entry_time <= 0)
            continue;

         if(current_time - entry_time < m_close_after_seconds)
            continue;

         if(CloseSelectedPosition(ticket, "time limit"))
            result = true;
        }

      return result;
   }

private:
   bool IsTargetSelectedPosition()
   {
      if(PositionGetString(POSITION_SYMBOL) != m_symbol)
         return false;
      if((ulong)PositionGetInteger(POSITION_MAGIC) != m_magic)
         return false;

      return true;
   }

   string PositionTypeText(const ENUM_POSITION_TYPE type)
   {
      if(type == POSITION_TYPE_BUY)
         return "BUY";
      if(type == POSITION_TYPE_SELL)
         return "SELL";

      return "UNKNOWN";
   }

   bool CloseSelectedPosition(const ulong ticket,
                              const string reason)
   {
      const ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      const double volume = PositionGetDouble(POSITION_VOLUME);

      ResetLastError();
      if(!m_trade.PositionClose(ticket, m_deviation_points))
        {
         Print("HITPositionLifecycleManager close failed: ticket=", ticket,
               " symbol=", m_symbol,
               " magic=", m_magic,
               " type=", PositionTypeText(type),
               " volume=", DoubleToString(volume, 2),
               " reason=", reason,
               " retcode=", m_trade.ResultRetcode(),
               " err=", GetLastError());
         return false;
        }

      Print("HITPositionLifecycleManager closed position: ticket=", ticket,
            " symbol=", m_symbol,
            " magic=", m_magic,
            " type=", PositionTypeText(type),
            " volume=", DoubleToString(volume, 2),
            " reason=", reason,
            " retcode=", m_trade.ResultRetcode());
      return true;
   }
};

#endif
