//+------------------------------------------------------------------+
//|                                                 ReportLayout.mqh |
//+------------------------------------------------------------------+
#ifndef REPORTLAYOUT_MQH
#define REPORTLAYOUT_MQH

#include "TradeStat.mqh"
#include "PdfBuilder.mqh"
//+------------------------------------------------------------------+
//| Formats a value that may be undefined (sentinel -1.0) as "N/A",  |
//| used for profit factor when there have been no losing trades.    |
//+------------------------------------------------------------------+
string FormatMaybeUndefined(double value, int digits)
  {
   if(value < 0.0)
      return("N/A");
   return(::DoubleToString(value, digits));
  }
//+------------------------------------------------------------------+
//| Draws the complete report page into pdf using the values in      |
//| stat. This function is shared between SymbolTradeReport.mq5,     |
//| which supplies statistics computed from live history, and        |
//| TestPdfReport.mq5, which supplies hand-built synthetic values,   |
//| guaranteeing both produce structurally identical PDF layouts.    |
//+------------------------------------------------------------------+
void BuildReportContent(CPdfBuilder &pdf, const CTradeStat &stat,
                        const string generated_at)
  {
   double left   = 72.0;  // 1 inch left margin
   double top    = 750.0; // near the top of a 792-point-tall page
   double line_h = 16.0;  // vertical spacing between text lines
   double y      = top;

//--- title and metadata block
   pdf.DrawText(left, y, 18, "Trade Analytics Report");
   y -= line_h * 1.5;

   string period = "Period: " +
                   ::TimeToString(stat.from, TIME_DATE) + " - " +
                   ::TimeToString(stat.to,   TIME_DATE);
   pdf.DrawText(left, y, 11, "Symbol: " + stat.symbol);
   pdf.DrawText(left + 220, y, 11, period);
   y -= line_h;
   pdf.DrawText(left, y, 9, "Generated: " + generated_at);
   y -= line_h * 1.5;

//--- "Summary Statistics" heading sits ABOVE the bordered box;
//--- stats_top is captured BEFORE drawing the heading so the border
//--- rect encloses only the data rows, not the section label itself.
//--- Previously stats_top was set after the heading, which placed the
//--- rect's top edge only 8 points above the last heading baseline,
//--- causing the 13-point cap-height to clip against the border line.
   double stats_top = y - line_h * 0.3; // 5 pts of breathing room above first row
   pdf.DrawText(left, y, 13, "Summary Statistics");
   y -= line_h * 1.2; // larger gap between heading and first data row

   double value_x = left + 220;

   pdf.DrawText(left, y, 10, "Total Trades");
   pdf.DrawText(value_x, y, 10, ::IntegerToString(stat.total_trades));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Winning Trades");
   pdf.DrawText(value_x, y, 10, ::IntegerToString(stat.win_trades));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Losing Trades");
   pdf.DrawText(value_x, y, 10, ::IntegerToString(stat.loss_trades));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Win Rate");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.win_rate, 1) + " %");
   y -= line_h;

   pdf.DrawText(left, y, 10, "Gross Profit");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.gross_profit, 2));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Gross Loss");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.gross_loss, 2));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Net Profit");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.net_profit, 2));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Profit Factor");
   pdf.DrawText(value_x, y, 10, FormatMaybeUndefined(stat.profit_factor, 2));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Average Win");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.average_win, 2));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Average Loss");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.average_loss, 2));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Expectancy per Trade");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.expectancy, 2));
   y -= line_h;

   pdf.DrawText(left, y, 10, "Max Drawdown");
   pdf.DrawText(value_x, y, 10, ::DoubleToString(stat.max_drawdown, 2));
   y -= line_h * 0.75;

//--- border rect drawn after the rows so it renders on top of nothing;
//--- the rect now wraps only the data rows, with the section heading
//--- sitting visibly above it as intended
   double stats_bottom = y;
   pdf.SetLineWidth(0.5);
   pdf.DrawRect(left - 8, stats_bottom, 468,
                stats_top - stats_bottom + line_h, false);

   y -= line_h * 2.0;

//--- equity curve section
   pdf.DrawText(left, y, 13, "Equity Curve");
   y -= line_h;

   double chart_x = left;
   double chart_w = 468.0;
   double chart_h = 160.0;
   double chart_y = y - chart_h;

//--- light grey chart background for visual contrast
   pdf.SetFillColor(0.96, 0.96, 0.97);
   pdf.DrawRect(chart_x, chart_y, chart_w, chart_h, true);

//--- chart border in mid-grey
   pdf.SetStrokeColor(0.70, 0.70, 0.72);
   pdf.SetLineWidth(0.5);
   pdf.DrawRect(chart_x, chart_y, chart_w, chart_h, false);

   int n = ::ArraySize(stat.equity_curve);
   if(n >= 2)
     {
      //--- find the value range, always including zero so the zero line
      //--- is meaningful even if every trade was profitable or every
      //--- trade was a loss
      double min_v = 0.0;
      double max_v = 0.0;
      for(int i = 0; i < n; i++)
        {
         if(stat.equity_curve[i] < min_v)
            min_v = stat.equity_curve[i];
         if(stat.equity_curve[i] > max_v)
            max_v = stat.equity_curve[i];
        }
      double range = max_v - min_v;
      if(range <= 0.0)
         range = 1.0; // guard against a flat curve producing a divide by zero

      //--- zero reference line in light grey
      double zero_y = chart_y + ((0.0 - min_v) / range) * chart_h;
      pdf.SetStrokeColor(0.75, 0.75, 0.77);
      pdf.SetLineWidth(0.4);
      pdf.DrawLine(chart_x, zero_y, chart_x + chart_w, zero_y);

      //--- map every equity curve point into the chart's coordinate box
      double xs[];
      double ys[];
      ::ArrayResize(xs, n);
      ::ArrayResize(ys, n);
      for(int i = 0; i < n; i++)
        {
         xs[i] = chart_x + (chart_w * i) / (n - 1);
         ys[i] = chart_y + ((stat.equity_curve[i] - min_v) / range) * chart_h;
        }

      //--- equity curve line in a strong teal blue
      pdf.SetStrokeColor(0.09, 0.53, 0.78);
      pdf.SetLineWidth(1.5);
      pdf.DrawPolyline(xs, ys, n);

      //--- reset stroke to black for anything drawn after
      pdf.SetStrokeColor(0.0, 0.0, 0.0);
      pdf.SetFillColor(0.0, 0.0, 0.0);
     }
  }

#endif // REPORTLAYOUT_MQH
//+------------------------------------------------------------------+