//+------------------------------------------------------------------+
//|                                          HeatmapTablePrinter.mqh |
//+------------------------------------------------------------------+
#ifndef HEATMAPTABLEPRINTER_MQH
#define HEATMAPTABLEPRINTER_MQH

#include "HeatmapTypes.mqh"

//+------------------------------------------------------------------+
//| CHeatmapTablePrinter                                             |
//| Prints the best and worst symbol-and-hour combinations by win    |
//| rate to the Experts tab, filtered to cells with a minimum        |
//| trade count.                                                     |
//+------------------------------------------------------------------+
class CHeatmapTablePrinter
  {
private:
   string                PadRight(string value, int width) const;
   void                  SortByWinRate(CHeatmapCell &cells[], int count) const;
   void                  PrintRow(const CHeatmapCell &cell) const;

public:
                     CHeatmapTablePrinter(void);
                    ~CHeatmapTablePrinter(void);

   void                  Print(const CHeatmapCell &cells_in[], int count,
                               int min_trades, int top_n) const;
  };

//+------------------------------------------------------------------+
//| Constructor: no member state to initialize.                      |
//+------------------------------------------------------------------+
CHeatmapTablePrinter::CHeatmapTablePrinter(void)
  {
  }

//+------------------------------------------------------------------+
//| Destructor: no dynamic resources to release.                     |
//+------------------------------------------------------------------+
CHeatmapTablePrinter::~CHeatmapTablePrinter(void)
  {
  }

//+------------------------------------------------------------------+
//| Print                                                            |
//| Filters cells to those with at least min_trades trades, sorts    |
//| the filtered copy by win rate descending, and prints the top and |
//| bottom top_n rows as the best and worst combinations.            |
//+------------------------------------------------------------------+
void CHeatmapTablePrinter::Print(const CHeatmapCell &cells_in[], int count,
                                 int min_trades, int top_n) const
  {
//--- keep only cells with enough trades to be worth trusting
   CHeatmapCell filtered[];
   ::ArrayResize(filtered, 0);
   for(int i = 0; i < count; i++)
     {
      if(cells_in[i].trade_count >= min_trades)
        {
         int n = ::ArraySize(filtered);
         ::ArrayResize(filtered, n + 1);
         filtered[n] = cells_in[i];
        }
     }
   int n = ::ArraySize(filtered);
   if(n == 0)
     {
      ::Print("HeatmapDashboard: no symbol/hour cell has at least ", min_trades, " trades");
      return;
     }
   SortByWinRate(filtered, n);
   string header = PadRight("Symbol", 12) + PadRight("Hour", 8) + PadRight("Trades", 10) +
                   PadRight("Win Rate", 12) + PadRight("Edge Ratio", 10);
//--- print the best combinations from the top of the sorted list
   int best_shown = (n < top_n) ? n : top_n;
   ::Print("Best symbol/hour combinations:");
   ::Print(header);
   for(int i = 0; i < best_shown; i++)
      PrintRow(filtered[i]);
//--- print the worst combinations from whatever remains below the best list,
//--- so a small filtered set never shows the same cell in both tables
   int remaining   = n - best_shown;
   int worst_shown = (remaining < top_n) ? remaining : top_n;
   ::Print("Worst symbol/hour combinations:");
   if(worst_shown <= 0)
      ::Print("(none remaining; fewer than ", 2 * top_n, " cells met the minimum trade count)");
   else
     {
      ::Print(header);
      for(int i = 0; i < worst_shown; i++)
         PrintRow(filtered[n - 1 - i]);
     }
  }
  
//+------------------------------------------------------------------+
//| SortByWinRate                                                    |
//| Sorts cells into descending order by win rate using a simple     |
//| bubble sort.                                                     |
//+------------------------------------------------------------------+
void CHeatmapTablePrinter::SortByWinRate(CHeatmapCell &cells[], int count) const
  {
   CHeatmapCell temp;
   for(int i = 0; i < count - 1; i++)
     {
      for(int j = 0; j < count - 1 - i; j++)
        {
         if(cells[j].win_rate_percent < cells[j + 1].win_rate_percent)
           {
            temp         = cells[j];
            cells[j]     = cells[j + 1];
            cells[j + 1] = temp;
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| PrintRow                                                         |
//| Prints one fixed-width row for a single cell, showing "N/A" for  |
//| the Edge ratio column when the ratio is undefined for that cell. |
//+------------------------------------------------------------------+
void CHeatmapTablePrinter::PrintRow(const CHeatmapCell &cell) const
  {
   string rr_text = cell.has_rr ? ::DoubleToString(cell.avg_rr, 2) : "N/A";
   string row = PadRight(cell.symbol, 12) + PadRight(::IntegerToString(cell.hour), 8) +
                PadRight(::IntegerToString(cell.trade_count), 10) +
                PadRight(::DoubleToString(cell.win_rate_percent, 1) + "%", 12) +
                PadRight(rr_text, 10);
   ::Print(row);
  }

//+------------------------------------------------------------------+
//| PadRight                                                         |
//| Pads a string with trailing spaces up to the given width, or     |
//| returns the original string unchanged if it already meets or     |
//| exceeds that width.                                              |
//+------------------------------------------------------------------+
string CHeatmapTablePrinter::PadRight(string value, int width) const
  {
   int need = width - ::StringLen(value);
   if(need <= 0)
      return(value);
   string result = value;
   for(int i = 0; i < need; i++)
      result += " ";
   return(result);
  }

#endif // HEATMAPTABLEPRINTER_MQH
//+------------------------------------------------------------------+