//+------------------------------------------------------------------+
//|                                    TradeTimingSummaryPrinter.mqh |
//+------------------------------------------------------------------+
#ifndef TRADETIMINGSUMMARYPRINTER_MQH
#define TRADETIMINGSUMMARYPRINTER_MQH

#include "TradeExcursionTypes.mqh"

//+----------------------------------------------------------------------+
//| CTradeTimingSummaryPrinter                                           |
//| Complements the two charts with an exact numerical summary printed   |
//| to the Experts tab: how many closed positions were analyzed, how     |
//| many were excluded for lack of tick data, the win/loss/breakeven     |
//| split, the mean entry efficiency, and the single best and single     |
//| worst entries by efficiency. This class performs its own scan of the |
//| trade array rather than depending on CEfficiencyStatistics, the same |
//| decoupling used by the calendar heatmap dashboard's summary printer, |
//| which computed its own weekday breakdown rather than reusing the grid|
//| mapper: a printer that only ever reads plain trade records stays easy|
//| to reason about on its own.                                          |
//+----------------------------------------------------------------------+
class CTradeTimingSummaryPrinter
  {
public:
                     CTradeTimingSummaryPrinter(void);
                    ~CTradeTimingSummaryPrinter(void);
   void              Print(const CTradeExcursion &trades[], int count) const;
  };

//+--------------------------------------------------------------------+
//| Constructor                                                        |
//| The printer holds no state between calls, so construction performs |
//| no work beyond default object creation.                            |
//+--------------------------------------------------------------------+
CTradeTimingSummaryPrinter::CTradeTimingSummaryPrinter(void)
  {
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//| No resources are owned by this class, so no cleanup is required. |
//+------------------------------------------------------------------+
CTradeTimingSummaryPrinter::~CTradeTimingSummaryPrinter(void)
  {
  }

//+-----------------------------------------------------------------------+
//| Print                                                                 |
//| Prints the position count, the tick-data exclusion count, the         |
//| win/loss/breakeven split, and, when at least one trade has a defined  |
//| efficiency, the mean efficiency and the single best and single worst  |
//| entries. A trade's net profit of exactly zero is counted as breakeven,|
//| never folded into the win or loss count, matching the same explicit   |
//| zero-classification rule used throughout this project. When no trade  |
//| has a defined efficiency, that section is skipped with an explicit    |
//| message rather than reporting a mean of zero or reading past the      |
//| end of an empty best/worst search.                                    |
//+-----------------------------------------------------------------------+
void CTradeTimingSummaryPrinter::Print(const CTradeExcursion &trades[],const int count) const
  {
   int excluded_no_ticks = 0;
   int win_count = 0, loss_count = 0, breakeven_count = 0;
   double efficiency_sum = 0.0;
   int efficiency_defined_count = 0;
   int best_index  = -1;
   int worst_index = -1;

   for(int i = 0; i < count; i++)
     {
      if(trades[i].m_tick_count <= 0)
         excluded_no_ticks++;

      //--- exact breakeven is its own explicit category, never a win or a loss
      if(trades[i].m_net_profit > 0.0)
         win_count++;
      else
         if(trades[i].m_net_profit < 0.0)
            loss_count++;
         else
            breakeven_count++;

      if(trades[i].m_efficiency_defined)
        {
         efficiency_sum += trades[i].m_efficiency;
         efficiency_defined_count++;
         if(best_index < 0 || trades[i].m_efficiency > trades[best_index].m_efficiency)
            best_index = i;
         if(worst_index < 0 || trades[i].m_efficiency < trades[worst_index].m_efficiency)
            worst_index = i;
        }
     }

   ::Print("Trade Entry Timing Summary");
   ::PrintFormat("Closed positions analyzed: %d  (excluded, no tick data: %d)", count, excluded_no_ticks);
   ::PrintFormat("Outcome breakdown: %d wins, %d losses, %d breakeven", win_count, loss_count, breakeven_count);

   if(efficiency_defined_count <= 0)
     {
      ::Print("No trades have a defined entry efficiency (every trade either lacked tick data or showed zero price movement).");
      return;
     }

   double mean_efficiency = efficiency_sum / efficiency_defined_count;
   ::PrintFormat("Mean entry efficiency across %d trades: %.3f", efficiency_defined_count, mean_efficiency);
   int best_digits  = (int)::SymbolInfoInteger(trades[best_index].m_symbol, SYMBOL_DIGITS);
   int worst_digits = (int)::SymbolInfoInteger(trades[worst_index].m_symbol, SYMBOL_DIGITS);
   ::PrintFormat("Best entry:  position #%.0f   efficiency %.3f   MAE %s   MFE %s",
                 (double)trades[best_index].m_position_id, trades[best_index].m_efficiency,
                 ::DoubleToString(trades[best_index].m_mae, best_digits), ::DoubleToString(trades[best_index].m_mfe, best_digits));
   ::PrintFormat("Worst entry: position #%.0f   efficiency %.3f   MAE %s   MFE %s",
                 (double)trades[worst_index].m_position_id, trades[worst_index].m_efficiency,
                 ::DoubleToString(trades[worst_index].m_mae, worst_digits), ::DoubleToString(trades[worst_index].m_mfe, worst_digits));
  }

#endif // TRADETIMINGSUMMARYPRINTER_MQH
//+------------------------------------------------------------------+