// reasampler_embed.h — the embedded TCP/MCP UI shell. Implements REAPER's
// IReaperUIEmbedInterface so the instrument draws a compact keymap/level strip inline in
// the track/mixer control panel. All embed messages arrive on REAPER's UI thread; nothing
// here runs in process(). Windows-only, guarded so a non-Windows build stays compilable.
// The strip's layout is pure (embed_strip.h, unit-tested); this shell marshals REAPER's
// messages to/from it. The strip is a read-only readout — the loaded capture across the
// keyboard with its root marked, plus the activity level.

#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include "pluginterfaces/base/funknown.h"

#include "core/instrument/map/sample_map.h"  // SampleChoice (the state the strip reflects)

// REAPER's VST3-side embed interface (vendored). Uses UNQUALIFIED Steinberg types, so it is
// pulled into the Steinberg namespace the same way reaper_bridge.cpp includes the host
// interface header. Its iid is DEFINEd (DEF_CLASS_IID) in reasampler_embed.cpp.
namespace Steinberg {
#include "reaper_vst3_interfaces.h"
}  // namespace Steinberg

namespace reasampler::vst {

class ReaSamplerProcessor;

using instrument::map::SampleChoice;

// Implements IReaperUIEmbedInterface. Lifetime is owned by the processor (sole unique_ptr,
// hands out AddRef'd references from queryInterface); the back-pointer to the processor is
// therefore always valid while this lives.
class ReaSamplerEmbed : public Steinberg::IReaperUIEmbedInterface {
public:
    explicit ReaSamplerEmbed(ReaSamplerProcessor* processor) : processor_(processor) {}

    // The one embed entry point, verified against reaper_plugin_fx_embed.h +
    // reaper_vst3_interfaces.h: our IEditController answers queryInterface for
    // IReaperUIEmbedInterface. msg is a REAPER_FXEMBED_WM_* value (aliased to Win32 WM_*)
    // — WM_IS_SUPPORTED, WM_CREATE/WM_DESTROY, WM_PAINT (parm2 = IBitmap*, parm3 =
    // DrawInfo*), WM_GETMINMAXINFO (parm3 = SizeHints*), mouse WM_* (return
    // RETNOTIFY_INVALIDATE to force a redraw). No plugin-owned HWND here (unlike the
    // IPlugView editor): REAPER hands a LICE bitmap per paint. UI thread only.
    Steinberg::TPtrInt embed_message(int msg, Steinberg::TPtrInt parm2,
                                     Steinberg::TPtrInt parm3) override;

    // FUnknown: lifetime is owned by the processor, not the host refcount, so
    // AddRef/release are no-ops and queryInterface answers only FUnknown +
    // IReaperUIEmbedInterface — the owning processor guarantees this outlives every
    // borrowed reference REAPER holds during embedding.
    Steinberg::tresult PLUGIN_API queryInterface(const Steinberg::TUID iid,
                                                 void** obj) override;
    Steinberg::uint32 PLUGIN_API addRef() override { return 1000; }
    Steinberg::uint32 PLUGIN_API release() override { return 1000; }

private:
#ifdef _WIN32
    // Draws the current strip into REAPER's supplied LICE bitmap. Returns true if it drew.
    bool paint(Steinberg::TPtrInt bitmap, Steinberg::TPtrInt drawInfo);
#endif

    // The loaded capture id + effective root (cheap in-process accessors, no bridge read).
    // `processor_` must be non-null.
    void refreshLoaded();

    // Snapshots the live bank + the instrument's loaded capture and effective root for the
    // next paint.
    void refresh();

    // Dirty-guard over refresh(): re-reads the bank blob only when the (cheap) generation
    // stamp changed since the last paint. The loaded capture + root are always refreshed
    // (cheap in-process accessors) so an edit reflects immediately. UI thread only.
    void maybeRefresh();

    ReaSamplerProcessor* processor_ = nullptr;
    // The bank generation last folded into samples_. -1 is an "unprimed" sentinel distinct
    // from a real generation 0, forcing the first maybeRefresh() to do a full read.
    std::int64_t lastSeenBankGeneration_ = -1;
    std::vector<SampleChoice> samples_;
    std::string loadedId_;   // the loaded capture's bank id; "" = nothing loaded
    int rootNote_ = 60;      // effective root: override, else the capture's own intrinsic
};

}  // namespace reasampler::vst
