<?php
/**
 * Shared strategy-selector architecture — Strategies module (2026-08-01).
 *
 * This deliberately does NOT reuse src/AccountPicker.php's
 * apRenderAccountPicker() function directly — that function's badge default
 * (apAccountLifecycleBadge()) is meaningless for a strategy (no
 * lifecycle_state), and forcing a strategy row through an "account"-shaped
 * data contract would be the same kind of awkward generalization
 * AccountPicker.php's own docblock explicitly warned against ("apFetchAccounts
 * is deliberately a NEW independent query function rather than a forced
 * generalization"). Instead, this file reuses the exact same *markup
 * classes* (.rn-account-picker / .rn-account-item / .rn-acct-extra /
 * .rn-show-more-accts / .rn-account-search) that assets/css/account-picker.css
 * and assets/js/account-picker.js already style/drive — those two files are
 * 100% generic (pure class-name selectors, no "account" semantics baked in),
 * confirmed by reading both before writing this file. So this is a second
 * *render function*, but the exact same CSS/JS/interaction pattern, with zero
 * duplicated styling or JS — one real implementation of the widget, reused.
 */

/**
 * Every active strategy for a user, ordered the same way
 * AccountPicker::apFetchAccounts() orders accounts — most-recently-used
 * first (via each strategy's most recent real trade), with trade count as
 * a tiebreaker for strategies used equally recently (rare) or never used
 * yet at all (falls back to creation order).
 */
function spFetchStrategies(string $userId, ScopedDb $db): array {
    // Excludes is_validation = 1 strategies — TRADERALIGN STRATEGY BUSINESS
    // RULES.docx redesign (2026-08-11). This picker feeds real trade-prep
    // (Trading Center → Strategies → Calculator) and the Dashboard/Reports/
    // Drafts strategy switcher — both are the "declared edge" domain the
    // redesign governs. Validation/practice strategies are a separate,
    // not-yet-redesigned concept (their own dedicated flow is
    // strategy-validation.php / journal-validation.php) and must stay out
    // of this picker so this domain's Strategy Change Event model is never
    // exercised against one.
    return $db->raw(
        "SELECT s.id, s.name, s.trading_style, s.current_version_id,
                sv.max_risk_per_trade_pct,
                (SELECT COUNT(*) FROM strategy_change_events sce WHERE sce.strategy_id = s.id) AS change_count,
                (SELECT COUNT(*) FROM trades t2
                   JOIN strategy_versions sv2 ON sv2.id = t2.strategy_version_id
                  WHERE sv2.strategy_id = s.id AND t2.status = 'closed' AND t2.deleted_at IS NULL
                    AND (t2.is_validation = 0 OR t2.is_validation IS NULL)) AS trade_count,
                (SELECT MAX(t3.captured_at) FROM trades t3
                   JOIN strategy_versions sv3 ON sv3.id = t3.strategy_version_id
                  WHERE sv3.strategy_id = s.id AND t3.deleted_at IS NULL) AS last_used
         FROM strategies s
         JOIN strategy_versions sv ON sv.id = s.current_version_id
         WHERE s.user_id = :uid AND s.is_active = 1 AND s.deleted_at IS NULL
           AND (s.is_validation = 0 OR s.is_validation IS NULL)
         ORDER BY (last_used IS NULL) ASC, last_used DESC, trade_count DESC, s.created_at DESC",
        [':uid' => $userId]
    );
}

/**
 * Validation Workflow counterpart to spFetchStrategies() above — same row
 * shape (so the shared spRenderStrategyPicker() widget works unmodified
 * either way), but is_validation flipped to 1: only ever exposes a
 * validating user's own validation strategy/strategies, never a real
 * (declared-edge) strategy. Used by public/strategies.php when the user's
 * active workflow is 'validation' (ValidationService::getWorkflowState()).
 */
function spFetchValidationStrategies(string $userId, ScopedDb $db): array {
    return $db->raw(
        "SELECT s.id, s.name, s.trading_style, s.current_version_id,
                sv.max_risk_per_trade_pct,
                (SELECT COUNT(*) FROM strategy_change_events sce WHERE sce.strategy_id = s.id) AS change_count,
                (SELECT COUNT(*) FROM trades t2
                   JOIN strategy_versions sv2 ON sv2.id = t2.strategy_version_id
                  WHERE sv2.strategy_id = s.id AND t2.status = 'closed' AND t2.deleted_at IS NULL
                    AND t2.is_validation = 1) AS trade_count,
                (SELECT MAX(t3.captured_at) FROM trades t3
                   JOIN strategy_versions sv3 ON sv3.id = t3.strategy_version_id
                  WHERE sv3.strategy_id = s.id AND t3.deleted_at IS NULL) AS last_used
         FROM strategies s
         JOIN strategy_versions sv ON sv.id = s.current_version_id
         WHERE s.user_id = :uid AND s.is_active = 1 AND s.deleted_at IS NULL
           AND s.is_validation = 1
         ORDER BY (last_used IS NULL) ASC, last_used DESC, trade_count DESC, s.created_at DESC",
        [':uid' => $userId]
    );
}

/**
 * The single active-strategy pointer. Added 2026-08-20, real bug reported
 * directly: the strategy active when a trader pressed "Proceed to
 * Calculator" did not reliably stay active through Calculator, Save,
 * Drafts, and everywhere else, so they had to go back to Trading Center
 * or Strategies and re-pick it just to find their own trade and its stats.
 *
 * Root cause (see migration_add_user_active_strategy.sql for the full
 * account): PHP $_SESSION['active_strategy_id'] was read in drafts.php but
 * never written anywhere, and dashboard.php/reports.php/sidebar.php relied
 * entirely on browser sessionStorage, which only ever caught up to the
 * correct strategy client-side, after the page had already rendered with
 * the wrong one.
 *
 * spRecordActiveStrategy() is the ONE place a strategy selection becomes
 * "the active strategy for the whole app," called only when a page
 * resolves a strategy from a genuinely explicit ?strategy_id= (a real pick
 * on the Strategies page, or a direct consequence of one), never merely
 * because a page fell through to its own default. It updates both the
 * fast, same-session cache ($_SESSION['strategies_strategy_id'], already
 * used by public/strategies.php itself) and the persistent, cross-login
 * DB pointer (user_active_strategy), scoped per workflow so switching
 * between Main and Validation can never leak one workflow's active
 * strategy into the other's pages.
 */
function spRecordActiveStrategy(string $userId, string $strategyId, ScopedDb $db, string $workflowState = 'main'): void {
    $_SESSION['strategies_strategy_id'] = $strategyId;
    $db->raw(
        "INSERT INTO user_active_strategy (user_id, workflow_state, strategy_id, updated_at)
         VALUES (:uid, :wf, :sid, NOW(6))
         ON DUPLICATE KEY UPDATE strategy_id = VALUES(strategy_id), updated_at = VALUES(updated_at)",
        [':uid' => $userId, ':wf' => $workflowState, ':sid' => $strategyId]
    );
}

/**
 * The single strategy this user most recently, explicitly selected (see
 * spRecordActiveStrategy() above): the real, persisted fallback every
 * trade-prep/dashboard/reports/drafts page now consults BEFORE defaulting
 * to "most recently created strategy". Scoped to the given workflow.
 * Returns null when nothing has ever been explicitly selected yet (a
 * brand new account/workflow, or every selection predates this feature).
 */
function spGetActiveStrategyId(string $userId, ScopedDb $db, string $workflowState = 'main'): ?string {
    $rows = $db->raw(
        "SELECT strategy_id FROM user_active_strategy WHERE user_id = :uid AND workflow_state = :wf LIMIT 1",
        [':uid' => $userId, ':wf' => $workflowState]
    );
    return $rows[0]['strategy_id'] ?? null;
}

/**
 * The shared picker widget — collapsed "Select strategy ▾" button, search
 * box, first-5-visible list, the rest behind Show More/Show Less. Same
 * collapsed (non-inline) rendering mode AccountPicker's Trading Center
 * pickers use, matching the "[ Strategy Selector ▼ ]" mockup exactly.
 */
function spRenderStrategyPicker(array $strategies, ?string $selectedId, string $baseUrl, array $baseParams = [], string $paramName = 'strategy_id'): void {
    $selected = null;
    foreach ($strategies as $s) { if ($s['id'] === $selectedId) { $selected = $s; break; } }
    // Plain strategy name — no "(vN)" (business rules §13: version numbers
    // are internal bookkeeping, never user-facing).
    $selectedLabel = $selected ? $selected['name'] : 'Select strategy';
    $initialVisible = 5;
    $total = count($strategies);
    $styleLabels = ['scalper' => 'Scalper', 'day_trader' => 'Day Trader', 'swing' => 'Swing', 'position' => 'Position'];
    ?>
    <div class="rn-account-picker">
        <button type="button" class="rn-account-picker-btn" onclick="rnToggleAccountPicker(this)">
            <span class="rn-account-picker-current"><?= htmlspecialchars($selectedLabel) ?></span>
            <span class="rn-account-picker-chev">▾</span>
        </button>
        <div class="rn-account-picker-panel" style="display:none">
            <input type="text" class="rn-account-search" placeholder="Search strategies…" oninput="rnFilterAccounts(this)">
            <div class="rn-account-list">
                <?php foreach ($strategies as $i => $s):
                    $isExtra = $i >= $initialVisible;
                    $styleLabel = $styleLabels[$s['trading_style']] ?? ucfirst(str_replace('_', ' ', (string)$s['trading_style']));
                    $riskPct = $s['max_risk_per_trade_pct'];
                    $sub = $styleLabel . ($riskPct !== null ? ' · ' . rtrim(rtrim(number_format((float)$riskPct, 2), '0'), '.') . '% risk' : '');
                    $linkParams = $baseParams;
                    $linkParams[$paramName] = $s['id'];
                    $href = $baseUrl . '?' . http_build_query($linkParams);
                    $changeCount = (int)($s['change_count'] ?? 0);
                    $changeBadge = $changeCount > 0 ? ($changeCount . ' change' . ($changeCount === 1 ? '' : 's')) : null;
                ?>
                <a href="<?= htmlspecialchars($href) ?>"
                   class="rn-account-item<?= $s['id'] === $selectedId ? ' rn-account-item-selected' : '' ?><?= $isExtra ? ' rn-acct-extra' : '' ?>"
                   style="<?= $isExtra ? 'display:none' : '' ?>"
                   data-search="<?= htmlspecialchars(strtolower($s['name'])) ?>">
                    <span class="rn-account-item-label"><?= htmlspecialchars($s['name']) ?></span>
                    <span class="rn-account-item-meta"><?= htmlspecialchars($sub) ?><?php if ($changeBadge): ?> <span class="rn-badge rn-badge-neutral"><?= htmlspecialchars($changeBadge) ?></span><?php endif; ?></span>
                </a>
                <?php endforeach; ?>
            </div>
            <?php if ($total > $initialVisible): ?>
            <button type="button" class="rn-show-more-accts" data-expanded="0"
                    data-more-label="Show More (<?= $total - $initialVisible ?> more)"
                    onclick="rnToggleAccountsMore(this)">Show More (<?= $total - $initialVisible ?> more)</button>
            <?php endif; ?>
        </div>
    </div>
    <?php
}
