// instrument_drop_win — the REAPER shell for S17 drop-and-load. See instrument_drop_win.h.
//
// Compiled into the reaper_reasampler MODULE. Includes reaper_plugin_functions.h WITHOUT
// REAPERAPI_IMPLEMENT (main.cpp owns the pointers; here they are extern via the WANT list).

#include "instrument_drop_win.h"

#include <string>

#include "app_version.h"      // vstPluginName() — the CHANNEL-correct FX name (stable/beta pairing)
#include "instrument_drop.h"  // infoNamesFxHotspot — the PURE, unit-tested hotspot classifier

#include "reaper_plugin.h"

#define REAPERAPI_MINIMAL
#define REAPERAPI_WANT_GetThingFromPoint
#define REAPERAPI_WANT_TrackFX_AddByName
#define REAPERAPI_WANT_TrackFX_Delete
#define REAPERAPI_WANT_TrackFX_SetNamedConfigParm
#define REAPERAPI_WANT_Undo_BeginBlock2
#define REAPERAPI_WANT_Undo_EndBlock2
#include "reaper_plugin_functions.h"

namespace reasampler {

FxDropTarget resolveFxDropTarget(int screenX, int screenY) {
    FxDropTarget out;
    char info[256] = {0};
    // GetThingFromPoint returns the track under the point (may be null for a non-track thing)
    // and fills `info` with what was hit. A non-empty info OR a non-null track means the point
    // is over REAPER's own UI; a null track with an empty info means the pointer has left
    // REAPER entirely (over another app / the desktop) — the OsDrag boundary.
    MediaTrack* track = GetThingFromPoint(screenX, screenY, info, sizeof(info));
    out.track = track;
    out.overReaperUi = (track != nullptr) || (info[0] != '\0');
    // S-VIEW-BUG-1: the hotspot is either the FX chain/floating window ("fx_*") OR the track/
    // mixer panel that hosts the FX button ("tcp*"/"mcp*"). The pure classifier owns the rule.
    out.overFxHotspot = (track != nullptr) && infoNamesFxHotspot(info);
    return out;
}

bool performInstrumentDrop(MediaTrack* track, const std::string& chunkBase64) {
    if (!track || chunkBase64.empty()) return false;

    // The CHANNEL-correct FX name: "VST3:ReaSampler 9000" on stable, "VST3:ReaSampler 9000
    // beta" on beta. Sourcing it from app_version::vstPluginName() (the same accessor the VST
    // factory display name derives from) keeps the pairing invariant intact — a beta extension
    // drops the beta VST, a stable extension the stable VST — with no literal to drift.
    const std::string fxName = "VST3:" + vstPluginName();

    // One undo point for the whole gesture (mirrors the bank-verb undo discipline). Both the
    // FX add and the state write are REAPER-undoable, so Ctrl-Z removes the instance cleanly.
    Undo_BeginBlock2(nullptr);

    // Negative `instantiate` => always create a NEW instance (verified in the header). recFX
    // = false: a normal track FX chain instance, not a record/monitoring FX.
    const int fxIndex = TrackFX_AddByName(track, fxName.c_str(), /*recFX=*/false,
                                          /*instantiate=*/-1);
    bool ok = false;
    if (fxIndex >= 0) {
        // Inject the instrument's OWN component-state blob (the dragged capture pre-selected)
        // via the documented vst_chunk write-parm. The blob was built by the shared writer
        // (instrument_drop::buildInstrumentDropChunk -> sample_map::serializeComponentState),
        // so these bytes are exactly what ReaSampler 9000's setState accepts.
        ok = TrackFX_SetNamedConfigParm(track, fxIndex, "vst_chunk", chunkBase64.c_str());
        if (!ok) {
            // All-or-nothing: if the chunk write fails, remove the empty FX instance we just
            // added so the track is left exactly as it was. TrackFX_Delete signature (verified
            // in reaper_plugin_functions.h:7236): bool TrackFX_Delete(MediaTrack*, int fx).
            TrackFX_Delete(track, fxIndex);
        }
    }

    // The undo label reflects the placement-of-the-player framing (not a capture, not an insert).
    Undo_EndBlock2(nullptr, "ReaSampler: drop capture onto FX chain", -1);
    return ok;
}

}  // namespace reasampler
