/* =====================================================================
 * rl_outcome_label.cu -- label assignment from trade outcomes.
 *
 * Grid  = (ceil(B / 32), 1, 1)
 * Block = (32, 1, 1)
 *
 * Per batch element:
 *   - If dones[b] > 0.5 (trade closed this step):
 *       label = 2 (Profit)  if reward > 0
 *       label = 0 (Loss)    if reward < -1e-6
 *       label = 1 (Timeout) otherwise
 *   - If dones[b] <= 0.5: labels[b] unchanged (remains sentinel -1
 *     or prior value from a previous done step).
 *
 * Labels are written IN-PLACE: caller initialises to -1 (sentinel)
 * and this kernel only overwrites on done transitions.
 *
 * No atomicAdd -- each thread writes at most one element at its
 * own unique index.
 *
 * Layout:
 *   rewards : [B]   IN  (float, per-step reward)
 *   dones   : [B]   IN  (float, 1.0 = episode done, 0.0 = not)
 *   labels  : [B]   IN/OUT (i32, written only when done)
 * ===================================================================== */

#define BLOCK_SIZE 32

extern "C" __global__ void rl_outcome_label(
    const float* __restrict__ rewards,   /* [B] */
    const float* __restrict__ dones,     /* [B] */
    int*         __restrict__ labels,    /* [B] */
    int b_size
) {
    int b = blockIdx.x * BLOCK_SIZE + threadIdx.x;
    if (b >= b_size) return;

    if (dones[b] > 0.5f) {
        float r = rewards[b];
        if (r > 0.0f) {
            labels[b] = 2;  /* Profit */
        } else if (r < -1e-6f) {
            labels[b] = 0;  /* Loss */
        } else {
            labels[b] = 1;  /* Timeout */
        }
    }
    /* else: leave labels[b] unchanged (sentinel -1 or prior). */
}

/* =====================================================================
 * rl_outcome_fill_sentinel -- fill labels buffer with sentinel -1.
 *
 * Grid  = (ceil(B / 32), 1, 1)
 * Block = (32, 1, 1)
 *
 * GPU-pure init: avoids memcpy_htod per mapped-pinned policy.
 * ===================================================================== */

extern "C" __global__ void rl_outcome_fill_sentinel(
    int* __restrict__ labels,   /* [B] */
    int b_size
) {
    int b = blockIdx.x * BLOCK_SIZE + threadIdx.x;
    if (b >= b_size) return;
    labels[b] = -1;
}
