#pragma once
#include <cstdint>

enum class Gesture { NONE, CLICK, LONG, LONG_RELEASE };
// Independent of GPIO/task scheduling: one long event, no trailing click.
class ButtonGesture {
public:
    static constexpr uint64_t LONG_MS = 600;
    static constexpr uint64_t DEBOUNCE_MS = 30;
    uint64_t epoch = 0;
    // Read-only diagnostics: the debounced state, not the raw GPIO level.
    bool down() const { return down_; }
    Gesture update(bool raw, uint64_t now, uint64_t current_epoch, bool allow_long) {
        if (raw != raw_) { raw_ = raw; changed_ = now; if (raw) epoch=current_epoch; }
        if (raw_ != down_ && now - changed_ >= DEBOUNCE_MS) {
            down_ = raw_;
            if (down_) { start_ = now; long_ = false; }
            else {
                if (long_) return Gesture::LONG_RELEASE;
                return epoch == current_epoch ? Gesture::CLICK : Gesture::NONE;
            }
        }
        if (down_ && raw_ && !long_ && epoch == current_epoch && allow_long && now-start_ >= LONG_MS) {
            long_ = true; return Gesture::LONG;
        }
        return Gesture::NONE;
    }
private:
    bool raw_ = false, down_ = false, long_ = false;
    uint64_t changed_ = 0, start_ = 0;
};
