/**
 * Trade stats reduction kernel.
 *
 * Reads portfolio_states[N, PORTFOLIO_STRIDE=43] and sums fields [14:19]
 * (win_count, loss_count, sum_wins, sum_losses, sum_returns, sum_sq_returns)
 * across all N episodes into a 6-float output buffer.
 * Uses shared-memory warp reduction (same pattern as monitoring_reduce).
 *
 * Launch config: grid=(1, 1, 1), block=(256, 1, 1).
 */

#define PORTFOLIO_STRIDE 43  // was 41; grown by Plan 3 D.4c PS_PRE_ENTRY_CONVICTION_{EMA,VAR_EMA} append. Kelly slots [14..19] unchanged.
#include "state_layout.cuh"

extern "C" __global__ void trade_stats_reduce(
    const float* __restrict__ portfolio_states, // [N * PORTFOLIO_STRIDE]
    float* out,                          // [6]: sums of ps[14..19]
    int          N
) {
    /* Per-warp scratch (max 32 warps in a 1024-thread block).
     * Was atomicAdd-into-shared — replaced with deterministic sequential
     * reduction by tid 0 in fixed warp-id order. Bit-stable across runs. */
    __shared__ float w_sums[32][6];

    int tid = threadIdx.x;
    int stride = blockDim.x;
    int warp_id = tid / 32;
    int lane = tid & 31;
    int num_warps = (blockDim.x + 31) / 32;

    // Thread-local accumulators — native f32
    float local_sums[6];
    for (int k = 0; k < 6; k++) local_sums[k] = 0.0f;

    for (int i = tid; i < N; i += stride) {
        int base = i * PORTFOLIO_STRIDE;
        for (int k = 0; k < 6; k++) {
            local_sums[k] = local_sums[k] + portfolio_states[base + PS_KELLY_WIN_COUNT + k];
        }
    }

    // Warp-level reduction (in-warp shuffle is deterministic by definition)
    for (int mask = 16; mask >= 1; mask >>= 1) {
        for (int k = 0; k < 6; k++) {
            local_sums[k] = local_sums[k] + __shfl_xor_sync(0xFFFFFFFF, local_sums[k], mask);
        }
    }

    // Each warp's lane 0 publishes into its own scratch slot — no race.
    if (lane == 0) {
        for (int k = 0; k < 6; k++) w_sums[warp_id][k] = local_sums[k];
    }
    __syncthreads();

    // tid 0 sequentially reduces warp slots in fixed order → bit-stable.
    if (tid == 0) {
        float total[6] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
        for (int w = 0; w < num_warps; w++) {
            for (int k = 0; k < 6; k++) total[k] += w_sums[w][k];
        }
        for (int k = 0; k < 6; k++) out[k] = total[k];
    }
}
