<?php

// Centralized coaching content for the Reports page (public/reports.php).
//
// Single source of truth so hover text can't drift into scattered, ad hoc
// $xxxTip strings across a 4500+ line file. Every entry is written like an
// experienced trading coach explaining a metric, not a spreadsheet caption:
// what it measures, why it matters, how it's worked out where that isn't
// obvious, what healthy/poor values usually look like, and one practical
// thing to do about it. Native `title` attribute is still the delivery
// mechanism (no new tooltip component — this is a content change, not a
// redesign), so entries use blank lines between short paragraphs, which
// browsers render as line breaks in a title tooltip.
//
// Usage: title attribute, htmlspecialchars(reportsCoach('key'))
// Tokens: entries may contain {like_this} — pass ['like_this' => $value] as
// the second argument to substitute a live number into the text.

const REPORTS_COACHING = [

    // ── Hero KPI tiles ─────────────────────────────────────────────────
    'hero.win_rate' => "Win Rate: the share of closed trades that finished profitable.\n\nA high win rate feels reassuring but doesn't by itself mean a strategy is profitable, a system that wins 80% of the time can still lose money if its average loss is much bigger than its average win. Read this alongside Profit Factor and Expectancy, not alone.\n\nIf win rate is falling while P&L holds steady or improves, that's usually a sign of fewer, better-sized losses rather than a problem.",
    'hero.profit_factor' => "Profit Factor: gross profit from winning trades divided by gross loss from losing trades.\n\nAbove 1.0 means the strategy made more than it lost over this period; below 1.0 means it lost money even if some trades won. As a rough guide: under 1.2 is fragile, 1.2-1.75 is solid, above 2.0 is strong, though this depends heavily on sample size and trade frequency.\n\nA low Profit Factor with a high win rate usually points to losses that run too large relative to wins, check whether stops are being honored.",
    'hero.expectancy' => "Expectancy: the average dollar result per trade, across every trade in this period (wins and losses combined).\n\nThis is the number that answers \"if I keep trading exactly like this, what do I make per trade on average?\" A positive expectancy with enough trades to trust it is the single clearest sign of a working edge; a negative one means the strategy is losing money on average even if some individual trades feel good.\n\nExpectancy near zero over a large sample usually means costs (spread, commission, slippage) are eating a real edge, check Stage 4's cost figures once reconciliation data exists.",
    'hero.total_trades' => "Total Trades: the number of trades that closed within the selected period.\n\nSmall samples produce noisy statistics: a handful of trades can make Win Rate or Profit Factor look far better or worse than the strategy's true long-run performance. Treat any metric on this page with real caution below roughly 20-30 trades, and prefer the Quarterly/Annual view once enough history exists.",
    'hero.net_profit' => "Net Profit: the sum of every closed trade's realized P&L this period (prop-firm accounts use challenge-capped P&L, personal accounts use uncapped broker P&L, per the platform's P&L rule).\n\nThis is a raw dollar total, not a rate, a large Net Profit from very few trades is a different (riskier) story than the same total spread across many trades. Cross-check against Total Trades and Expectancy before drawing conclusions.",
    'hero.max_drawdown' => "Max Drawdown: the largest peak-to-trough decline in account equity during this period.\n\nThis is a risk metric, not a profitability metric, a strategy can be net profitable and still have suffered a large drawdown along the way. Smaller, shallower drawdowns generally mean steadier, more sustainable risk-taking; a drawdown that approaches a prop firm's own limit is a real warning sign worth acting on immediately, not just noting.",

    // ── 4-Stage Summary top tiles ──────────────────────────────────────
    'fs.total_trades' => "Total Trades this period, compared against the prior period of the same length. A rising trade count isn't automatically good or bad, check whether it's coming with steady or improving Win Rate and Expectancy, or whether volume is increasing while quality declines (a common early sign of overtrading).",
    'fs.win_rate' => "Win Rate for this period specifically (not all-time), see Hero Win Rate for the general explanation. The delta shown against the prior period is the fastest way to see whether execution is trending in the right direction.",
    'fs.net_pnl' => "Total Net P&L for every trade closed within this specific period. Compared against the prior period of equal length so a genuine trend (not just a lucky stretch) is easier to spot.",
    'fs.ending_balance' => "Ending Balance: the account's real balance as of now (an all-time, anchored fact, not scoped to just this period). The period-over-period delta shown here is an approximation equal to this period's own net P&L, and assumes no deposits or withdrawals happened mid-period.",
    'fs.max_drawdown' => "Max Drawdown for this period, shown alongside what percentage of the account's balance that represents, a $500 drawdown means very different things on a $5,000 account versus a $500,000 one.",
    'fs.expectancy' => "Expectancy for this period specifically, see Hero Expectancy for the general explanation. Comparing this period's expectancy against the account's all-time expectancy (shown in the Strategy Performance Alert, when triggered) is the fastest way to tell whether a strategy is actually improving or just having a good stretch.",

    // ── 4-Stage row concepts (parameterized by {stage}) ────────────────
    'stage_row.adherence' => "{stage} Adherence: the share of trades that stayed within tolerance of what this stage's own comparison point declared (see the row's own caption for exactly what's being compared). This is the single clearest execution-discipline number on the page: low adherence with otherwise-fine P&L usually means the strategy is being outgrown by its own trader, not that the strategy itself is broken.",
    'stage_row.risk' => "{stage} Risk: the average % of account balance risked per trade at this stage. Consistent risk sizing (a tight, repeatable number) is generally healthier than a wide range, even if the average looks fine, wide swings usually mean sizing is being decided emotionally rather than systematically.",
    'stage_row.rr' => "{stage} Reward:Risk: the average ratio of potential/realized profit to risk at this stage, expressed as X:1. Higher isn't automatically better if it comes with a much lower win rate, Expectancy is what actually determines whether a given R:R and win-rate combination is profitable.",
    'stage_row.session' => "{stage} Trading Session: the distribution of which market session (Sydney/Tokyo/London/New York) these trades fell in. Useful for spotting whether performance is concentrated in (or dragged down by) a specific session, cross-check against the Session Performance analysis elsewhere in Reports for the win-rate breakdown by session.",
    'stage_row.instrument' => "{stage} Instrument: the distribution of which instruments these trades were in. A strategy declared for a narrow instrument list that keeps drifting into others is a real signal worth investigating, either the declared list is stale, or discipline around instrument selection is slipping.",
    'stage_row.timeframe' => "{stage} Timeframe: the chart timeframe (e.g. M15/H1/H4) these trades were actually taken on. Trading a strategy meaningfully off its intended timeframe changes its real risk/reward profile even if every other rule is followed correctly.",

    'stage1.strategy_adherence' => "Strategy Adherence (Stage 1): the share of trades that stayed within tolerance of the strategy's own declared max risk per trade. This measures whether the trader is following their own written plan, not whether the plan itself is good. Chronic over-risking here is one of the strongest predictors of an eventual breach.",
    'stage2.calculator_adherence' => "Calculator Adherence (Stage 2): the share of trades where the calculator's own saved numbers (entry/SL/TP/lot size, risk %, R:R) are internally geometrically consistent with each other. A mismatch here usually means a value was edited by hand after the calculator computed it, or a price was entered with a typo, worth a quick audit of whichever trades are flagged.",
    'stage3.execution_adherence' => "Execution Adherence (Stage 3): of trades with both a planned and a confirmed entry price and lot size, the share where the actual fill stayed within a normal tolerance of the plan (0.1% on price, 5% on lot size, wide enough to absorb ordinary broker rounding, tight enough to catch a real deviation). Consistently low adherence here usually means orders are being adjusted in the moment rather than executed as planned.",
    'stage3.executed_risk' => "Executed Risk (Stage 3): Stage 2's planned risk %, scaled by how much the actual lot size differed from the planned lot size. This approximates real risk taken assuming the stop-loss distance itself didn't move between planning and confirming the trade (SL adjustments aren't yet factored in, a known limitation, not a bug).",
    'stage3.executed_rr' => "Executed RR (Stage 3): the average realized R-multiple (P&L ÷ planned max loss) across both wins and losses this period. This is the single number that best answers \"how many R am I actually capturing per trade,\" independent of any one big winner or loser skewing a simple win-rate view.",
    'stage4.reconciled_adherence' => "Reconciled Adherence (Stage 4): of broker-reconciled trades, the share where the MT5-verified lot size matched the plan within tolerance. This is the most trustworthy adherence number on the page once reconciliation data exists, since it's checked against the broker's own record rather than a self-report.",
    'stage4.actual_broker_risk' => "Actual Broker Risk (Stage 4): the planned risk %, scaled by the broker-verified (not self-reported) lot size, for reconciled trades only. The gap between this and Stage 2's Planned Risk is the truest measure of real execution slippage on sizing.",
    'stage4.actual_rr' => "Actual RR (Stage 4): average realized R-multiple on winning trades only, computed from broker-verified reconciliation data. Compare against Stage 3's Executed RR (wins and losses, self-reported), a large gap between the two is worth investigating once enough reconciled trades exist.",
    'stage4.instrument_confirmed' => "Broker Match: of trades with both a manually-recorded actual instrument and broker reconciliation, the share where the two agree. A mismatch here means the instrument typed in at resolution didn't match what MT5 actually shows, worth double-checking before trusting the manual figure on that trade.",
    'stage4.timeframe_manual' => "Timeframe here is manually captured at trade resolution, not broker-verified, MT5 statements carry open/close timestamps and the traded symbol, but not which chart timeframe the trader was looking at. Reconciliation can confirm the instrument and lot size but not this field; treat it as self-reported.",

    // ── Commentary mini-tiles ──────────────────────────────────────────
    'commentary.discipline_score' => "Discipline Score: whether execution held steady across this period, by comparing the first half against the second half (same period, split in two). A score near 50 means no meaningful change either way; well above 50 means discipline visibly improved as the period went on; well below means it deteriorated. Needs a reasonable trade count to mean anything, see the tier note if one is shown.",
    'commentary.consistency_score' => "Consistency Score: how tightly risk sizing and realized R-multiples clustered around their own averages this period, versus swinging wildly trade to trade. High consistency with a modest average is usually more sustainable than a high average built on a few outlier trades. Needs a reasonable trade count to mean anything, see the tier note if one is shown.",
    'commentary.improvement' => "Improvement vs Prev Period: the change in win rate versus the immediately prior period of the same length. A positive number means trades are landing more often now than last period; treat one period's swing as a data point, not a verdict, especially at low trade counts.",

    // ── Classification grades ──────────────────────────────────────────
    'classification.a_plus' => "A+ (Disciplined Win): the trade followed the plan from entry through exit with no meaningful execution deviation, and it won. This is the outcome every trade should aim for: not just a profitable result, but a clean, repeatable process behind it.",
    'classification.a' => "A (Controlled Loss / Breakeven): the trade followed the plan and either broke even or lost within the planned risk. A controlled loss is not a failure, it's the cost of correctly executing a strategy that doesn't win every time. Worth celebrating discipline here even though the outcome wasn't a win.",
    'classification.b' => "B (Elevated Win): the trade won, but by a large enough margin relative to its own planned max loss that it's worth a second look at whether the result was earned by the plan or by a lucky outsized move. Not a problem by itself, but a cluster of these is worth reviewing.",
    'classification.c' => "C (Loss High Risk / Tilt Warning / Revenge Trade): the trade shows signs of over-risking, emotional decision-making, or trading immediately after a prior loss to \"win it back.\" This is the clearest signal for where discipline broke down this {period}, usually the fastest path to finding what's actually costing money.",

    // ── Intent vs Reality — Execution Gap ──────────────────────────────
    'gap.entry_precision' => "Entry Precision: the share of trades where the confirmed actual entry price landed within 0.1% of the planned entry price. Consistently low precision usually means orders are being chased or adjusted after the calculator plan was set, rather than executed as planned.",
    'gap.stop_precision' => "Stop Precision: the share of trades where the confirmed actual stop-loss matched the planned stop-loss within 0.1%. A stop that keeps moving from the plan is one of the most common ways a controlled-risk strategy quietly turns into an uncontrolled one.",
    'gap.tp_precision' => "TP Precision: of winning trades with a recorded exit price, the share that landed on one of the strategy's own declared take-profit levels within tolerance. Low precision here usually means exits are being taken early (leaving profit on the table) or extended past target (giving back gains) rather than following the plan.",
    'gap.lot_precision' => "Lot Size Precision: the share of trades where the confirmed actual lot size matched the planned lot size within a 5% tolerance (wide enough to absorb ordinary broker lot-step rounding). A real, persistent gap here, not just occasional rounding, usually means position size is being adjusted manually after the calculator already set it.",
    'gap.over_risk' => "Over-Risk Occurrences: trades that risked meaningfully more than the strategy's own declared limit, beyond the normal lot-rounding tolerance already built into this figure. This is scored per instrument class (forex majors and metals each get their own tolerance band derived from this account's real trade history) so ordinary contract-size rounding isn't mistaken for a real risk breach. Trades where no valid lot size on that instrument could have hit the declared target at all are excluded here and counted separately under Contract-Constrained, one is trader behavior, the other is an instrument limitation, and they're never mixed together.",
    'gap.contract_constrained' => "Contract-Constrained: trades where the declared risk target was never mathematically reachable: even the instrument's broker-minimum lot size, at this account's balance, already risks more than the declared limit (e.g. a coarse-contract instrument like Coffee on a small account). This is a structural instrument/contract limitation, not over-risking, it's computed using the same sizing formula the Calculator itself uses when a calculated lot size would round below the broker minimum. A high count here usually means the declared risk % is unrealistic for this instrument at this account size, not that discipline broke down.",
    'gap.rr_drift' => "RR Drift: the gap between the strategy's own declared reward:risk ratio and what the calculator actually planned this period, on average. A strategy that consistently plans a lower R:R than it declares is quietly changing its own math, even if every trade is executed perfectly, the strategy's real expectancy will differ from its backtested one.",

    // ── Portfolio Summary / Boundary Analysis ──────────────────────────
    'portfolio.total_accounts' => "Total Accounts: every prop-firm account currently tracked, regardless of outcome (active, breached, passed, funded). This is the denominator every other Portfolio Summary percentage is measured against.",
    'portfolio.combined_pnl' => "Combined P&L: every tracked prop-firm account's challenge-capped P&L for this period, summed together. Because it's capped at each account's own breach/target boundary, this reflects what the accounts actually counted toward pass/fail outcomes, not the uncapped dollar result a trade might otherwise show.",
    // Real bug found and fixed 2026-08-18 (Reports verification pass): the
    // Live Account Analytics Portfolio Summary card's <h3> tooltip was
    // reusing this exact prop-firm-worded entry verbatim ("challenge-capped
    // P&L", "breach/target boundary", "pass/fail outcomes"), none of which
    // apply to a personal/live account. New, correctly-worded entry for
    // that one call site.
    'portfolio.combined_pnl_live' => "Combined P&L: every tracked live account's real broker P&L (or projected P&L for a trade not yet reconciled) for this period, summed together. This is the uncapped, real trading result across every personal account, there is no challenge boundary or pass/fail outcome on a live account for this figure to be capped against.",
    'portfolio.active' => "Active: accounts currently in an ongoing phase (not yet breached, passed, or funded). The right number to watch here is trend over time relative to Breached, not the raw count alone.",
    'portfolio.breached' => "Breached: accounts that hit a hard rule limit (usually max drawdown or daily loss) and were disqualified from that attempt. A meaningfully high breach rate relative to Passed is the strongest signal that risk per trade or per day is set too aggressively for the rules being traded under, see Boundary Analysis below for the real breach-severity numbers.",
    'portfolio.passed' => "Passed: accounts that cleared every phase's profit target within its rules and moved on (to the next phase, or to funded status). This reflects an account having passed at least once in its history, not necessarily its current phase.",
    'portfolio.funded' => "Funded: accounts currently live with real firm capital after clearing every evaluation phase. This is the actual outcome the whole evaluation process exists to produce.",
    'portfolio.avg_days_to_breach' => "Avg Days to Breach: the average time between account creation and a breach event, across breached accounts with a recorded breach date. A very short average (same-day breaches) usually points to risk sizing that's fundamentally too large for the account's rules, not bad luck on any single trade.",
    'portfolio.avg_days_to_pass' => "Avg Days to Pass: the average time between account creation and a pass event, across passed accounts with a recorded pass date. Useful as a rough planning benchmark for how long a typical evaluation attempt takes under this trading approach.",

    'boundary.breach_severity' => "Avg Breach Severity: how far past the drawdown/loss limit the account's real (uncapped) result went at the moment of breach, as a % of the limit itself. A severity well over 100% usually means the triggering loss was large and fast, not a slow drift past the line, worth reviewing position sizing on the specific trades that caused it.",
    'boundary.pass_margin' => "Typical Pass Margin: how far past the profit target the account finished at the moment it passed, as a % of the target. A large margin suggests room to trade slightly smaller and still pass comfortably; a margin near 0% suggests the pass was tight and worth reviewing for repeatability.",
    'boundary.near_miss' => "Near-Miss Distance: accounts currently within 10% of their drawdown/daily-loss limit but not yet breached. These are the accounts most worth checking first, a single oversized loss on any of them could end the attempt.",
    'boundary.behavior_patterns' => "Behavior Patterns Leading to Breaches: the trader-recorded reasons behind past breaches on this account type, tallied by frequency. \"Not recorded\" reflects legacy breaches from before reason-capture existed, not a real pattern. A concentration in one specific reason is the clearest place to focus a rule-compliance review.",

    // ── Capital Flow ────────────────────────────────────────────────────
    'capital.deposits' => "Total Deposits: the sum of each personal account's initial funding plus any capital added later. This is a portfolio event, not a trading result, it says nothing about whether the trading itself is profitable.",
    'capital.withdrawals' => "Total Withdrawals: capital taken out of personal accounts. Regular withdrawals from a genuinely profitable account are healthy; withdrawals that exceed real trading profit mean the account is shrinking regardless of what the P&L figures show.",
    'capital.net_flow' => "Net Capital Flow: Total Deposits minus Total Withdrawals. This measures cash movement only; Combined P&L (computed purely from closed-trade outcomes) is the number that actually reflects trading performance, the two are intentionally kept separate.",

    // ── Instrument / leaderboard tables ────────────────────────────────
    'instrument.performance' => "Instrument Performance: the top instruments by absolute P&L impact this period. A single instrument dominating both the best and worst trades usually means it's simply the most-traded one, not necessarily the best or worst edge, check Win Rate and Trades alongside P&L before concluding either way.",
    'leaderboard.top_performing' => "Top Performing Accounts: ranked by trading result this period, not by final outcome. An account can rank highly here even if it later breached (or already has), the ranking measures how well it traded, which is a separate question from whether it survived its own rules. Hover an individual row for the specific reason it's ranked where it is.",
    // Same class of fix as leaderboard.needing_attention_live above: "breached"
    // is a prop-firm-only lifecycle outcome (see CLAUDE.md's Lifecycle Rule),
    // a live/personal account is either still active or closed, never
    // "breached". Live's own ranking rationale is generated per-row by
    // reports.php already (its own real reason, not this shared header text).
    'leaderboard.top_performing_live' => "Top Performing Accounts: ranked by trading result this period, not by final outcome. An account can rank highly here even if it later closed at a loss, the ranking measures how well it traded, which is a separate question from what eventually happened to it. Hover an individual row for the specific reason it's ranked where it is.",
    'leaderboard.needing_attention' => "Accounts Needing Attention: prop-firm accounts currently at or past half of their drawdown or daily-loss limit. This list exists to be checked first, before it grows: an account that's already used half its buffer has much less room left for a single bad trade than the raw percentage might suggest.",
    // Real bug found and fixed 2026-08-18 (Reports verification pass): the
    // Live Accounts "Accounts Needing Attention" card reused this exact
    // prop-firm-worded entry ("drawdown or daily-loss limit"), a limit that
    // doesn't exist for a personal account (challenge_accounts only applies
    // to prop_firm accounts). The live card's real rule is different too
    // (10% drawdown from the account's own historical peak equity, or a
    // realized net loss on an active account, see reports.php's own
    // $liveAttentionAccounts comment) and needs its own correctly-worded entry.
    'leaderboard.needing_attention_live' => "Accounts Needing Attention: live accounts currently drawn down at least 10% from their own historical peak equity, or showing a realized net loss while still active. Personal accounts have no firm-imposed drawdown limit, this threshold is this app's own judgment call for what's worth checking first, not a rule set by anyone else.",
    'leaderboard.most_breached' => "Most Severely Breached: ranked by the real, uncapped result at the moment of breach (Total Breach Payload), not the period-scoped capped P&L shown elsewhere. This is deliberately the harshest, most honest view of a breach: what actually happened to the account, unconstrained by the reporting cap.",
    'leaderboard.longest_surviving' => "Longest-Surviving Accounts: accounts that both lasted at least 30 days AND closed at least one real trade in that time (a dormant, never-traded account surviving on paper isn't the same as a genuinely long-running one). Trading Consistency shows roughly how often the account was actually traded during that span.",
    'retrospective.active_duration' => "Active Duration: the time between account creation and closure, not a measure of how much it was traded. \"Same-day account\" means the account was opened and closed within the same calendar day, a real, valid outcome (often a fast breach, or an account that was closed deliberately), not a data error.",
    'leaderboard.closed_retrospective' =>"Closed Account Retrospective: a look back at what happened on accounts that are no longer active, using their full trading history (not scoped to the currently selected period, since a closed account's history is a fixed, unchanging fact).",

    // ── Time Progress / Data Completeness (2026-07-28 second refinement
    // pass, item 2) — two deliberately separate metrics that answer
    // different questions. Never merge these back into one entry: Time
    // Progress depends only on today's date; Data Completeness depends only
    // on trade count. A trader can be early in the calendar period with a
    // large sample, or late in the period with almost none — both states
    // are real, and conflating them into one "X% complete" number hides
    // which one is actually true. ─────────────────────────────────────────
    'progress.time' => "Time Progress: how far through YOUR reporting window today's date falls, not the raw calendar.\n\nThe window starts on the later of the period's calendar start or your first trade in this view (whichever is later), so a trader who opens a prop-firm account in July doesn't see Annual Time Progress already reading 50% in July, as if the months before they existed counted against them.\n\nThis is still pure date math (it depends only on today's date and your first-trade date, not on how many trades you've logged), it says nothing about how much real trading evidence exists; see Data Completeness for that.",
    'progress.data_completeness' => "Data Completeness: how much real, closed-trade evidence exists for this period, independent of the calendar. This depends ONLY on trade count, never on today's date: a trader could be 5 trades into a brand-new week with strong completeness, or fully through a quiet month with almost none. Read it alongside Time Progress, not instead of it, early + thin means wait; early + full means the pattern may already be real; late + thin means the period was just quiet, not unreliable.",

    // ── Advanced Statistics ─────────────────────────────────────────────
    'advstat.sortino' => "Sortino Ratio: like Sharpe, but only penalizes downside volatility (losing trades), not all variability. A strategy with big winners and small, controlled losses can have a strong Sortino even with high overall variance, because the variance that matters (the downside) is small.",
    'advstat.sharpe' => "Sharpe Ratio: risk-adjusted return, measuring how much return was earned per unit of total volatility (wins and losses both count against it). Higher generally means steadier, more consistent returns for the risk taken, but it penalizes big winning trades the same way it penalizes big losing ones, which is why Sortino is often the more intuitive read for a trading strategy specifically.",
    'advstat.calmar' => "Calmar Ratio: annualized return divided by max drawdown. A high Calmar means the strategy's gains have been large relative to its worst equity dip; a low one means the drawdown risked to get here looks expensive relative to what it earned.",
    'advstat.recovery' => "Recovery Factor: net profit divided by max drawdown. Answers \"how many times over did this strategy earn back its worst drawdown,\" a factor above 1 means it's more than recovered; below 1 means the current profit hasn't yet made up for the worst dip along the way.",
    'advstat.risk_of_ruin' => "Risk of Ruin: an estimate of the probability this strategy's current risk-per-trade and edge combination eventually blows the account, if trading continued unchanged indefinitely. Even a small-looking percentage compounds over a long enough trading career, this number exists to be taken seriously, not just glanced at.",
    'advstat.strategy_consistency' => "Strategy Consistency: how similar this strategy's results have been trade to trade, versus a wide spread of outcomes. Two strategies can have identical average expectancy with very different consistency, the less consistent one is harder to size correctly and more likely to produce an emotionally difficult losing streak even while \"on track\" long-term.",
];

/**
 * Look up a coaching entry by key, with optional {token} substitution and a
 * {stage} shortcut for the parameterized stage_row.* entries.
 */
function reportsCoach(string $key, array $vars = []): string {
    $text = REPORTS_COACHING[$key] ?? '';
    if ($text === '') return '';
    foreach ($vars as $token => $value) {
        $text = str_replace('{' . $token . '}', (string)$value, $text);
    }
    return $text;
}
