#pragma once

#include <functional>
#include <string>
#include <vector>

/**
 * Trigger engine that detects edge crossings in a stream of (time, value)
 * samples.  Entirely render-thread owned — no cross-thread access.
 *
 * Usage:
 *   1. configure() + arm()
 *   2. Each render frame, call feed_new() with samples since last call.
 *      Returns true the first frame the trigger fires.
 *   3. When fired, call capture_pre_and_post() with the signal buffer.
 *   4. Check post_complete(now) each frame until post-trigger window fills.
 *   5. disarm() or re-arm after capture.
 */
class TriggerEngine {
public:
    enum class Edge  { Rising, Falling, Either };
    enum class Mode  { Single, Normal };
    enum class State { Idle, Armed, Fired, Complete };

    TriggerEngine();

    void configure(Edge edge, double threshold, Mode mode,
                   double pre_sec, double post_sec);

    void arm();
    void disarm();

    State  state()        const { return state_; }
    double trigger_time() const { return trig_time_; }
    double post_end_time() const { return trig_time_ + post_sec_; }

    /**
     * Feed new samples (render thread).  Returns true if trigger just fired.
     * new_t and new_v are arrays of length n, in chronological order.
     */
    bool feed_new(const double* new_t, const double* new_v, size_t n);

    /**
     * After trigger fires, call each frame.  Returns true once
     * current_latest_time >= trigger_time + post_sec.
     */
    bool post_complete(double current_latest_time) const;

    /** Optional callback when trigger fires. */
    std::function<void()> on_trigger;

    // Trigger edge/threshold for drawing reference lines
    double    threshold() const { return threshold_; }
    Edge      edge()      const { return edge_; }

private:
    Edge   edge_      = Edge::Rising;
    double threshold_ = 0.0;
    Mode   mode_      = Mode::Single;
    double pre_sec_   = 0.01;
    double post_sec_  = 0.09;

    State  state_     = State::Idle;
    double trig_time_ = 0.0;

    double prev_val_  = 0.0;
    bool   has_prev_  = false;
};
