// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
// SPDX-License-Identifier: AGPL-3.0-or-later

/**
 * @file sleep_sched.cpp
 * @brief Dynamic sleep-cycle scheduler decision core (see sleep_sched.h).
 */

#include "services/sleep_sched/sleep_sched.h"

#if DETWS_ENABLE_SLEEP_SCHED

uint32_t detws_sleep_next(uint32_t now, uint32_t last_active_ms, const DetwsSleepCfg *cfg)
{
    if (!cfg)
        return 0;

    uint32_t idle = (uint32_t)(now - last_active_ms); // wrap-safe unsigned delta
    if (idle < cfg->idle_ms)
        return 0; // active recently: stay awake

    uint32_t ceil_ms = cfg->max_ms < cfg->min_ms ? cfg->min_ms : cfg->max_ms;
    if (cfg->ramp_ms == 0)
        return ceil_ms; // no ramp: go straight to the deepest window

    // Grow the window by doubling for every ramp_ms of idle past the threshold, clamped to the ceiling.
    // The pre-shift ceiling check keeps the doubling from overflowing.
    uint32_t doublings = (idle - cfg->idle_ms) / cfg->ramp_ms;
    uint32_t window = cfg->min_ms ? cfg->min_ms : 1;
    for (uint32_t i = 0; i < doublings; i++)
    {
        if (window >= ceil_ms || window > ceil_ms / 2)
        {
            window = ceil_ms;
            break;
        }
        window <<= 1;
    }
    if (window > ceil_ms)
        window = ceil_ms;
    if (window < cfg->min_ms)
        window = cfg->min_ms;
    return window;
}

#endif // DETWS_ENABLE_SLEEP_SCHED
