// render_isolation.cpp — see the header.
//
// Compiled into the reaper_reasampler module. Includes reaper_plugin_functions.h
// WITHOUT REAPERAPI_IMPLEMENT — main.cpp is the one TU that defines the API
// pointers; here they are extern.

#include "shell/capture/render_isolation.h"

#include <cstddef>

#include "core/capture/track_topology.h"  // directChildIndices

#define REAPERAPI_MINIMAL
#define REAPERAPI_WANT_CountTracks
#define REAPERAPI_WANT_GetTrack
#define REAPERAPI_WANT_GetMediaTrackInfo_Value
#define REAPERAPI_WANT_SetMediaTrackInfo_Value
#define REAPERAPI_WANT_GetTrackNumSends
#define REAPERAPI_WANT_GetTrackSendInfo_Value
#define REAPERAPI_WANT_SetTrackSendInfo_Value
#include "reaper_plugin_functions.h"

namespace reasampler::capture {

namespace {

// GetTrackNumSends / *TrackSendInfo_Value category: < 0 selects the RECEIVE list
// (SDK header ~3644, ~3676).
constexpr int kReceivesCategory = -1;

}  // namespace

UpstreamIsolation::UpstreamIsolation(MediaTrack* track)
    : track_(track)
{
    if (!track_) return;

    // One pass over the track list for both the depth deltas and this track's index;
    // the pure walk turns the flat delta list into the direct-child set. The master
    // is absent from GetTrack's index space (it is reached only via GetMasterTrack)
    // and has no send-to-parent to cut, so nothing is missed by ignoring it.
    const int total = CountTracks(nullptr);
    std::vector<MediaTrack*> tracks;
    std::vector<int>         depths;
    tracks.reserve(static_cast<std::size_t>(total < 0 ? 0 : total));
    depths.reserve(static_cast<std::size_t>(total < 0 ? 0 : total));
    int parentIndex = -1;
    for (int i = 0; i < total; ++i)
    {
        MediaTrack* tr = GetTrack(nullptr, i);
        tracks.push_back(tr);
        depths.push_back(tr ? static_cast<int>(
                                  GetMediaTrackInfo_Value(tr, "I_FOLDERDEPTH"))
                            : 0);
        if (tr == track_) parentIndex = i;
    }

    for (int idx : directChildIndices(depths, parentIndex))
    {
        MediaTrack* child = tracks[static_cast<std::size_t>(idx)];
        if (!child) continue;
        // B_MAINSEND: "track sends audio to parent" (SDK header ~2238/~2957).
        children_.push_back({child, GetMediaTrackInfo_Value(child, "B_MAINSEND")});
        SetMediaTrackInfo_Value(child, "B_MAINSEND", 0.0);
    }

    const int receives = GetTrackNumSends(track_, kReceivesCategory);
    receiveMutes_.reserve(static_cast<std::size_t>(receives < 0 ? 0 : receives));
    for (int i = 0; i < receives; ++i)
    {
        receiveMutes_.push_back(
            GetTrackSendInfo_Value(track_, kReceivesCategory, i, "B_MUTE"));
        SetTrackSendInfo_Value(track_, kReceivesCategory, i, "B_MUTE", 1.0);
    }
}

UpstreamIsolation::~UpstreamIsolation()
{
    for (std::size_t i = 0; i < receiveMutes_.size(); ++i)
        SetTrackSendInfo_Value(track_, kReceivesCategory, static_cast<int>(i),
                               "B_MUTE", receiveMutes_[i]);
    for (const ChildSend& c : children_)
        SetMediaTrackInfo_Value(c.track, "B_MAINSEND", c.mainSend);
}

}  // namespace reasampler::capture
