// rl_avg_win_loss_ema_update.cu — Layer 4 (Kelly) input EMA producer.
//
// Tracks observed per-trade avg_win and avg_loss magnitudes in USD as
// EMAs. Kelly fraction uses R-multiple = avg_win / avg_loss together
// with win_rate to derive the safe Kelly bet size.
// Spec: docs/superpowers/specs/2026-05-30-adaptive-risk-management-design.md
//
// Inputs:
//   rewards[b]    f32 — per-batch realized pnl delta (shaped) this step
//   dones[b]      f32 — 1.0 if a trade closed this step, else 0.0
//
// Outcome derived inline: win = (done & reward > 0); loss = (done & reward < 0).
//
// Outputs:
//   ISV[RL_AVG_WIN_USD_EMA_INDEX  = 678]  (positive USD)
//   ISV[RL_AVG_LOSS_USD_EMA_INDEX = 679]  (positive USD, magnitude)
//
// Bootstrap semantics per `pearl_first_observation_bootstrap`:
//   sentinel = 0.0; first non-zero closed-trade step replaces directly.
//
// Per `feedback_no_atomicadd`: single-thread single-block (sums sequentially).
// Per `feedback_cpu_is_read_only`: pure device kernel.
// Per `feedback_isv_for_adaptive_bounds`: EMA-α structural smoothing
// parameter (same as ema_update_per_step convention).

#include <stdint.h>

#define RL_AVG_WIN_USD_EMA_INDEX   678
#define RL_AVG_LOSS_USD_EMA_INDEX  679
#define EMA_ALPHA_FAST             0.05f
// B-6 ISV-driven adaptive asymmetric Wiener-α (2026-06-01 spec).
// α_slow_eff = α_slow_min + (α_fast − α_slow_min) × trust_eff
// trust_eff = trust(n) × stability(CV)
//   trust(n) = min(1, cum_dones / n_full_threshold)         [Phase 1]
//   stability(CV) = exp(-CV × cv_gain)                       [Phase 2]
// Slot 721 α_slow_min, 722 n_full_threshold, 723 cv_gain.
// Welford triplet for reward_magnitude provides CV (Phase 2).
#define RL_EMA_ALPHA_SLOW_MIN_INDEX       721
#define RL_EMA_TRUST_FULL_THRESHOLD_INDEX 722
#define RL_EMA_CV_GAIN_INDEX              723
#define RL_CUMULATIVE_DONES_INDEX         660
#define RL_REWARD_MAG_VAR_COUNT_INDEX     615
#define RL_REWARD_MAG_VAR_MEAN_INDEX      616
#define RL_REWARD_MAG_VAR_M2_INDEX        617

extern "C" __global__ void rl_avg_win_loss_ema_update(
    float*       __restrict__ isv,
    const float* __restrict__ rewards,                   // [b_size] shaped pnl
    const float* __restrict__ dones,                     // [b_size] 1.0 = close
    int                       b_size
) {
    if (threadIdx.x != 0 || threadIdx.y != 0 || threadIdx.z != 0) return;
    if (blockIdx.x  != 0 || blockIdx.y  != 0 || blockIdx.z  != 0) return;

    // Sum per-trade win/loss magnitudes across the batch.
    float sum_win  = 0.0f;
    float sum_loss = 0.0f;
    int   n_win    = 0;
    int   n_loss   = 0;
    for (int b = 0; b < b_size; ++b) {
        if (dones[b] < 0.5f) continue;
        const float p = rewards[b];
        if (p > 0.0f) {
            sum_win  += p;
            n_win    += 1;
        } else if (p < 0.0f) {
            sum_loss += fabsf(p);
            n_loss   += 1;
        }
    }

    // B-6 ISV-driven adaptive asymmetric Wiener-α (Bayesian shrinkage).
    // α_slow_eff blends α_slow_min → α_fast as data confidence grows.
    const float a_slow_min  = isv[RL_EMA_ALPHA_SLOW_MIN_INDEX];
    const float a_fast      = EMA_ALPHA_FAST;
    const float n_trades    = isv[RL_CUMULATIVE_DONES_INDEX];
    const float n_full      = isv[RL_EMA_TRUST_FULL_THRESHOLD_INDEX];
    const float cv_gain     = isv[RL_EMA_CV_GAIN_INDEX];

    // Phase 1: data-quantity trust (resets at fold boundary via reset_session_state)
    float trust = (n_full > 0.0f) ? fminf(1.0f, n_trades / n_full) : 1.0f;

    // Phase 2: signal-volatility gain (set cv_gain=0 to disable)
    if (cv_gain > 0.0f) {
        const float wf_count = isv[RL_REWARD_MAG_VAR_COUNT_INDEX];
        if (wf_count > 1.0f) {
            const float wf_m2   = isv[RL_REWARD_MAG_VAR_M2_INDEX];
            const float wf_mean = isv[RL_REWARD_MAG_VAR_MEAN_INDEX];
            const float wf_var  = wf_m2 / (wf_count - 1.0f);
            const float cv      = (wf_mean > 1e-6f) ? sqrtf(wf_var) / wf_mean : 0.0f;
            const float stability = expf(-cv * cv_gain);
            trust *= stability;
        }
    }

    const float a_slow_eff = a_slow_min + (a_fast - a_slow_min) * trust;

    if (n_win > 0) {
        const float step_avg = sum_win / (float)n_win;
        const float prev     = isv[RL_AVG_WIN_USD_EMA_INDEX];
        // avg_win: slow-up (skeptical of wins), fast-down (correct quickly)
        const float alpha = (step_avg > prev) ? a_slow_eff : a_fast;
        isv[RL_AVG_WIN_USD_EMA_INDEX] = (1.0f - alpha) * prev + alpha * step_avg;
    }

    if (n_loss > 0) {
        const float step_avg = sum_loss / (float)n_loss;
        const float prev     = isv[RL_AVG_LOSS_USD_EMA_INDEX];
        // avg_loss: fast-up (admit losses, safety), slow-down (slow forget)
        const float alpha = (step_avg > prev) ? a_fast : a_slow_eff;
        isv[RL_AVG_LOSS_USD_EMA_INDEX] = (1.0f - alpha) * prev + alpha * step_avg;
    }
}
