// embed_strip.cpp — see embed_strip.h. Pure math; no host types.

#include "core/instrument/ui/embed_strip.h"

#include <algorithm>

namespace reasampler::instrument::ui {

namespace {

int clampNote(int n) {
    if (n < 0) return 0;
    if (n > kEmbedKeyCount - 1) return kEmbedKeyCount - 1;
    return n;
}

// Maps a key boundary (0..128) to an x pixel; keyEdge==128 maps to the band's right. A
// span's left uses floor(low) and its right uses floor(high+1), tiling adjacent spans
// without a seam.
int keyEdgeToX(int bandLeft, int bandWidth, int keyEdge) {
    if (keyEdge <= 0) return bandLeft;
    if (keyEdge >= kEmbedKeyCount) return bandLeft + bandWidth;
    return bandLeft + (keyEdge * bandWidth) / kEmbedKeyCount;
}

}  // namespace

EmbedLayout layoutEmbed(int w, int h) {
    const int cw = std::max(0, w);
    const int ch = std::max(0, h);

    EmbedLayout out;

    // Fixed height at the bottom, but never so much that the keymap falls below its
    // minimum; on a very short area the band yields to the keymap entirely.
    int bandH = std::min(kEmbedLevelBandHeight, ch);
    if (ch - bandH < kEmbedKeymapMinHeight) {
        bandH = std::max(0, ch - kEmbedKeymapMinHeight);
    }
    const int keymapBottom = ch - bandH;

    out.keymap = Rect::ltrb(0, 0, cw, keymapBottom);
    out.levelBand = Rect::ltrb(0, keymapBottom, cw, ch);
    return out;
}

Rect keySpanRect(const EmbedLayout& layout, int lowNote, int highNote) {
    const Rect& band = layout.keymap;
    const int bandWidth = std::max(0, band.width);

    int lo = clampNote(lowNote);
    int hi = clampNote(highNote);
    if (lo > hi) lo = hi;  // defensive: a malformed span collapses rather than inverts

    const int leftX = keyEdgeToX(band.x, bandWidth, lo);
    const int rightX = keyEdgeToX(band.x, bandWidth, hi + 1);
    return Rect::ltrb(leftX, band.y, std::max(leftX, rightX), band.bottom());
}

Rect levelFillRect(const EmbedLayout& layout, double level) {
    const Rect& band = layout.levelBand;
    if (band.width <= 0 || band.height <= 0) return Rect{};
    double l = level;
    if (l < 0.0) l = 0.0;
    if (l > 1.0) l = 1.0;
    const int fillW = static_cast<int>(l * band.width);
    if (fillW <= 0) return Rect{};
    return Rect::ltrb(band.x, band.y, band.x + fillW, band.bottom());
}

}  // namespace reasampler::instrument::ui
