// crates/ml/src/cuda_pipeline/sharpe_per_bar_kernel.cu
//
// SP15 Phase 1.1 — unified per-bar sharpe.
// Used by both train and val paths with identical formula and identical
// window definition. Eliminates the SP14-era sharpe_ema (per-batch EMA)
// vs sharpe_annualised (val × sqrt(525600)) split.
//
// Computes: mean(pnl), std(pnl) via 2-pass block-tree-reduce; emits
// sharpe = mean / max(std, 1e-12).
// Annualisation is the host-side caller's responsibility:
//     sharpe_annualised = out[2] * sqrt(N_bars_per_year)
//
// Single-block launch, BLOCK=256. No atomicAdd (per feedback_no_atomicadd):
// reduction uses shared-memory tree-reduce only. `__threadfence_system()`
// flushes mapped-pinned writes before the host reads via `read_volatile`.

extern "C" __global__ void sharpe_per_bar_kernel(
    const float* __restrict__ pnl,
    int          n,
    float*       __restrict__ out  /* [mean, std, sharpe] */
) {
    if (blockIdx.x != 0) return;

    const int tid   = (int)threadIdx.x;
    const int BLOCK = (int)blockDim.x;
    __shared__ float reduce_buf[256];
    __shared__ float mean_shared;

    // Pass 1: sum → mean
    float local_sum = 0.0f;
    for (int i = tid; i < n; i += BLOCK) {
        local_sum += pnl[i];
    }
    reduce_buf[tid] = local_sum;
    __syncthreads();
    for (int s = BLOCK / 2; s > 0; s >>= 1) {
        if (tid < s) reduce_buf[tid] += reduce_buf[tid + s];
        __syncthreads();
    }
    if (tid == 0) {
        mean_shared = (n > 0) ? reduce_buf[0] / (float)n : 0.0f;
    }
    __syncthreads();

    // Pass 2: sum of squared deviations → std
    float local_sq = 0.0f;
    for (int i = tid; i < n; i += BLOCK) {
        float d = pnl[i] - mean_shared;
        local_sq += d * d;
    }
    reduce_buf[tid] = local_sq;
    __syncthreads();
    for (int s = BLOCK / 2; s > 0; s >>= 1) {
        if (tid < s) reduce_buf[tid] += reduce_buf[tid + s];
        __syncthreads();
    }
    if (tid == 0) {
        float var = (n > 0) ? reduce_buf[0] / (float)n : 0.0f;
        float std = sqrtf(fmaxf(var, 1e-12f));
        out[0] = mean_shared;
        out[1] = std;
        out[2] = (std > 0.0f) ? mean_shared / std : 0.0f;
        __threadfence_system();
    }
}
