//+------------------------------------------------------------------+
//|                                            SessionAggregator.mqh |
//+------------------------------------------------------------------+
#ifndef SESSIONAGGREGATOR_MQH
#define SESSIONAGGREGATOR_MQH

#include "SessionEnums.mqh"

#define SESSION_TYPE_COUNT 5

//+------------------------------------------------------------------+
//| CSessionAggregator                                               |
//| Groups deal records by session type and computes net P&L, win    |
//| rate inputs, trade count, and average hold time for each.        |
//+------------------------------------------------------------------+
class CSessionAggregator
  {
private:
   string                SessionName(ENUM_TRADING_SESSION session_type) const;

public:
                     CSessionAggregator(void);
                    ~CSessionAggregator(void);

   int                   Aggregate(const CDealRecord &records[], int count,
                                   CSessionMetrics &metrics[]);
   void                  ComputeTotals(const CSessionMetrics &metrics[], int count,
                                       int &total_trades_out, double &total_win_rate_out,
                                       double &total_net_pnl_out);
  };

//+------------------------------------------------------------------+
//| Constructor: no member state to initialize.                      |
//+------------------------------------------------------------------+
CSessionAggregator::CSessionAggregator(void)
  {
  }

//+------------------------------------------------------------------+
//| Destructor: no dynamic resources to release.                     |
//+------------------------------------------------------------------+
CSessionAggregator::~CSessionAggregator(void)
  {
  }

//+------------------------------------------------------------------+
//| Aggregate                                                        |
//| Groups the provided deal records by session type and computes    |
//| net P&L, win rate, trade count, and average hold time for each.  |
//| Returns the number of metrics entries populated.                 |
//+------------------------------------------------------------------+
int CSessionAggregator::Aggregate(const CDealRecord &records[], int count,
                                  CSessionMetrics &metrics[])
  {
//--- size the metrics array to hold every possible session type
   ::ArrayResize(metrics, SESSION_TYPE_COUNT);
   int                   trade_count     = 0;
   int                   win_count       = 0;
   double                net_pnl         = 0.0;
   long                  total_hold_time = 0;
   long                  hold_seconds    = 0;
   ENUM_TRADING_SESSION  current_type    = SESSION_SYDNEY;
//--- compute metrics for each of the five possible session types
   for(int s = 0; s < SESSION_TYPE_COUNT; s++)
     {
      current_type    = (ENUM_TRADING_SESSION)s;
      trade_count     = 0;
      win_count       = 0;
      net_pnl         = 0.0;
      total_hold_time = 0;
      //--- scan every deal record for matches to the current session type
      for(int i = 0; i < count; i++)
        {
         if(records[i].session_type != current_type)
            continue;
         trade_count++;
         net_pnl += records[i].profit;
         if(records[i].profit > 0.0)
            win_count++;
         hold_seconds     = (long)(records[i].close_time - records[i].open_time);
         total_hold_time += hold_seconds;
        }
      //--- populate the metrics entry for this session type
      metrics[s].session_type     = current_type;
      metrics[s].name             = SessionName(current_type);
      metrics[s].trade_count      = trade_count;
      metrics[s].win_count        = win_count;
      metrics[s].net_pnl          = net_pnl;
      metrics[s].total_hold_time  = total_hold_time;
      //--- guard against division by zero for sessions with no trades
      if(trade_count > 0)
         metrics[s].average_hold_time = (double)total_hold_time / (double)trade_count;
      else
         metrics[s].average_hold_time = 0.0;
     }
   return(SESSION_TYPE_COUNT);
  }

//+------------------------------------------------------------------+
//| ComputeTotals                                                    |
//| Folds every session's metrics into an account-wide total trade   |
//| count, win rate, and net P&L, summed across all session types.   |
//+------------------------------------------------------------------+
void CSessionAggregator::ComputeTotals(const CSessionMetrics &metrics[], int count,
                                       int &total_trades_out, double &total_win_rate_out,
                                       double &total_net_pnl_out)
  {
   int    total_trades  = 0;
   int    total_wins    = 0;
   double total_pnl     = 0.0;
//--- sum trade count, win count, and net P&L across every session
   for(int i = 0; i < count; i++)
     {
      total_trades += metrics[i].trade_count;
      total_wins   += metrics[i].win_count;
      total_pnl    += metrics[i].net_pnl;
     }
   total_trades_out = total_trades;
//--- guard against division by zero when no trades exist at all
   if(total_trades > 0)
      total_win_rate_out = ((double)total_wins / (double)total_trades) * 100.0;
   else
      total_win_rate_out = 0.0;
   total_net_pnl_out = total_pnl;
  }

//+------------------------------------------------------------------+
//| SessionName                                                      |
//| Returns the display name for a given session type.               |
//+------------------------------------------------------------------+
string CSessionAggregator::SessionName(ENUM_TRADING_SESSION session_type) const
  {
   switch(session_type)
     {
      case SESSION_SYDNEY:
         return("Sydney");
      case SESSION_TOKYO:
         return("Tokyo");
      case SESSION_LONDON:
         return("London");
      case SESSION_NEW_YORK:
         return("New York");
      default:
         return("Unknown");
     }
  }

#endif // SESSIONAGGREGATOR_MQH
//+------------------------------------------------------------------+