#pragma once
// The ASYNC realtime-record seam: begin/tick/abort. capture.h keeps the shared
// CaptureRequest/CaptureResult types, the offline backend, and shared helpers.
// Implemented by capture_realtime_shell.cpp; driven by exactly one caller
// (realtime_lifecycle).
//
// CSurf_OnRecord starts the transport on REAPER's audio thread and returns
// immediately — it does not block until the range completes. Blocking the main
// thread would freeze REAPER's UI, so the backend is driven across timer ticks
// instead: begin() starts and returns at once; tick() (called from the same
// OnTimer that runs session.poll()) advances the in-flight record.
//
// The two backends deliberately share NO interface — do not reintroduce one.
// Offline is headless + immediate (one synchronous capture() call); realtime is
// transport-driven + async. A shared interface would make offline fake a
// lifecycle it doesn't have (tick() always Done on first call).
//
// REAPER-free like capture.h: MediaTrack is forward-declared there, never
// dereferenced here; the REAPER-facing TU is capture_realtime_shell.cpp.

#include <memory>
#include <vector>

#include "shell/capture/capture.h"  // CaptureRequest / CaptureResult / MediaTrack fwd

namespace reasampler::capture {

// One tick's verdict from the in-flight record.
enum class RealtimeTickStatus {
    InProgress,  // still recording — call tick() again next timer tick
    Done,        // finished (range end reached, or the user stopped) — `result` is set
    Failed,      // an error tore the capture down — `result.message` explains
};

struct RealtimeTickResult {
    RealtimeTickStatus status = RealtimeTickStatus::InProgress;
    CaptureResult      result;  // meaningful only when status == Done or Failed
};

// The opaque in-flight capture state: the snapshot of everything to restore
// (temp track + its sends from the source tracks, other tracks' I_RECARM,
// transport, edit cursor, time selection) and the record's own project handle.
// Defined in capture_realtime_shell.cpp; forward-declared here to stay REAPER-free.
//
// restore()/teardown is idempotent and lives ON THIS OBJECT, not a function-scope
// RAII guard, because the record spans ticks — no single stack frame outlives it.
// Every terminal path (completion, user stop, error, project switch, unload)
// funnels through the same restore, safe to call once from whichever fires.
class RealtimeCaptureState;

// Out-of-line deleter so callers can own a unique_ptr to the opaque
// RealtimeCaptureState without its full (REAPER-typed) definition.
struct RealtimeCaptureStateDeleter {
    void operator()(RealtimeCaptureState* p) const noexcept;
};
using RealtimeCaptureHandle =
    std::unique_ptr<RealtimeCaptureState, RealtimeCaptureStateDeleter>;

// Captures by recording in realtime into a hidden temp track, then moves the
// recorded file into the bank as a Sample. For sources offline render can't do
// (hardware, performed FX) and as the true pre-FX-dry path (I_RECMODE_FLAGS
// &3==1 — the only pre-FX tap in the SDK). Dialog-free: never invokes the
// offline-render progress window.
//
// Non-bit-identical by nature; offline stays the deterministic default.
// Non-destructive across every terminal path is harder here than offline
// because the record spans ticks: snapshot + restore live on
// RealtimeCaptureState, not a function-scope RAII destructor.
//
// TRACK scope only (this increment): records the selected track's own output
// (item + track's own FX/fader/pan, pre-parent), matching offline's track
// scope. Needs no FxBypassGuard — a send tapping a track's output is naturally
// pre-parent, so the tap is chain-independent by construction. Item realtime
// is deferred (UnsupportedMode).
class RealtimeRecordBackend {
public:
    // Validates the request (track scope, non-empty range, >=1 source track,
    // active+saved project, transport idle), snapshots state, creates the hidden
    // temp track, routes a send from each source track into it, arms, and
    // CSurf_OnRecord — then returns immediately. `sourceTracks` are resolved by
    // the caller; CaptureRequest itself stays REAPER-free. On success the
    // returned unique_ptr owns the in-flight state; on failure returns nullptr
    // with `outFailure` filled (nothing left mutated).
    RealtimeCaptureHandle begin(const CaptureRequest& request,
                                const std::vector<MediaTrack*>& sourceTracks,
                                CaptureResult& outFailure);

    // Reads the transport (bound to the record's OWN project handle so a project
    // switch can't confuse it); on a terminal verdict stops the transport,
    // finalizes the recorded file (Done) or reports the failure (Failed), then
    // restores all snapshotted state. After Done/Failed the state is spent.
    RealtimeTickResult tick(RealtimeCaptureState& state);

    // Force-terminate now without waiting for the range end: stops transport,
    // finalizes best-effort or abandons, restores all snapshotted state. For
    // shutdown/project-switch paths where the record must not leak a temp
    // track/armed track/altered transport. Idempotent.
    RealtimeTickResult abort(RealtimeCaptureState& state);
};

} // namespace reasampler::capture
