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

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

#include <algorithm>

#include "core/instrument/ui/sample_bands.h"  // kPad

namespace reasampler::instrument::ui {

namespace {

// The toolbar row carries the whole control run, so it is taller than the Browse modal's
// plain kTitleHeight bar — the velocity knob cell (knob over label) sets the floor. Both
// rows still fit the band the allocator hands out (kTitleHeight + kChromeRowHeight).
constexpr int kToolbarHeight = 58;
constexpr int kStripBandHeight = 30;

constexpr int kRunGap = 6;  // between adjacent items of the toolbar run
constexpr int kChanSegW = 52;
constexpr int kChanSegH = 18;
// The loop enable's segments carry a two-word label, so they are wider than Mono|Stereo's.
// If the title slot ever fails to hold its text at the editor's floor, THIS narrows — the
// floor does not move.
constexpr int kLoopSegW = 58;
constexpr int kVelCellW = 56;
constexpr int kHoldCellW = 56;  // the bake Hold cell, same grammar as the velocity cell
constexpr int kVelLabelH = 16;
constexpr int kPreviewBtnW = 64;
constexpr int kRunButtonH = 24;  // Browse and Preview

constexpr int kPreviewGlyphMinH = 6;
constexpr int kPreviewGlyphMaxH = 14;
constexpr int kPreviewGlyphPad = 4;  // clearance between the glyph and the button edge

}  // namespace

ChromeRects chromeRects(const Rect& chrome, int knobSize) {
    ChromeRects r;
    if (chrome.empty()) return r;

    const int toolbarH = std::min(kToolbarHeight, chrome.height);
    r.toolbar = Rect::ltrb(chrome.x, chrome.y, chrome.right(), chrome.y + toolbarH);
    r.controls = Rect::ltrb(chrome.x, r.toolbar.bottom(), chrome.right(), chrome.bottom());

    const Rect& row = r.toolbar;
    const auto topFor = [&row](int h) { return row.y + (row.height - h) / 2; };
    const auto leftOf = [&row](int edge, int w) { return std::max(row.x, edge - w); };

    // The fixed run, right to left: Browse, Mono|Stereo, Loop Off|On, velocity cell, preview,
    // bake, hold.
    // The velocity-curve button that used to sit here now lives in the deck's VELOCITY group.
    const int navH = std::min(kRunButtonH, row.height);
    const int navTop = topFor(navH);
    const int navRight = std::max(row.x, row.right() - kPad);
    r.navBrowse = Rect::ltrb(leftOf(navRight, kNavButtonWidth), navTop, navRight,
                             navTop + navH);

    const int chanTop = topFor(kChanSegH);
    const int chanRight = leftOf(r.navBrowse.x, kRunGap);
    r.chanStereo = Rect::ltrb(leftOf(chanRight, kChanSegW), chanTop, chanRight,
                              chanTop + kChanSegH);
    r.chanMono = Rect::ltrb(leftOf(r.chanStereo.x, kChanSegW), chanTop, r.chanStereo.x,
                            chanTop + kChanSegH);

    const int loopRight = leftOf(r.chanMono.x, kRunGap);
    r.loopOn = Rect::ltrb(leftOf(loopRight, kLoopSegW), chanTop, loopRight,
                          chanTop + kChanSegH);
    r.loopOff = Rect::ltrb(leftOf(r.loopOn.x, kLoopSegW), chanTop, r.loopOn.x,
                           chanTop + kChanSegH);

    const int cellH = std::min(row.height, knobSize + kVelLabelH);
    const int cellTop = topFor(cellH);
    const int cellRight = leftOf(r.loopOff.x, kRunGap);
    r.velCell = Rect::ltrb(leftOf(cellRight, kVelCellW), cellTop, cellRight, cellTop + cellH);
    const int knobLeft = r.velCell.x + (r.velCell.width - knobSize) / 2;
    r.velKnob = Rect::ltrb(knobLeft, r.velCell.y, knobLeft + knobSize,
                           r.velCell.y + std::min(knobSize, cellH));
    r.velLabel = Rect::ltrb(r.velCell.x, r.velKnob.bottom(), r.velCell.right(),
                            r.velCell.bottom());

    const int prevTop = topFor(std::min(kRunButtonH, row.height));
    const int prevRight = leftOf(r.velCell.x, kRunGap);
    r.preview = Rect::ltrb(leftOf(prevRight, kPreviewBtnW), prevTop, prevRight,
                           prevTop + std::min(kRunButtonH, row.height));

    const int bakeRight = leftOf(r.preview.x, kRunGap);
    r.bake = Rect::ltrb(leftOf(bakeRight, kBakeButtonWidth), prevTop, bakeRight,
                        prevTop + std::min(kRunButtonH, row.height));

    // Hold: the same knob-cell grammar as the velocity cell, immediately left of Bake.
    const int holdRight = leftOf(r.bake.x, kRunGap);
    r.holdCell = Rect::ltrb(leftOf(holdRight, kHoldCellW), cellTop, holdRight,
                            cellTop + cellH);
    const int holdKnobLeft = r.holdCell.x + (r.holdCell.width - knobSize) / 2;
    r.holdKnob = Rect::ltrb(holdKnobLeft, r.holdCell.y, holdKnobLeft + knobSize,
                            r.holdCell.y + std::min(knobSize, cellH));
    r.holdLabel = Rect::ltrb(r.holdCell.x, r.holdKnob.bottom(), r.holdCell.right(),
                             r.holdCell.bottom());

    // The title takes what the run leaves; clamped so a narrow window collapses it rather
    // than inverting it.
    r.title = Rect::ltrb(row.x + kPad, row.y, std::max(row.x + kPad, r.holdCell.x - kRunGap),
                         row.bottom());

    if (r.controls.empty()) return r;
    // The strip row belongs to the strip alone — inset only by the shared band pad, so it
    // lines up with the waveform band directly beneath it.
    const int stripH = std::min(kStripBandHeight, r.controls.height);
    const int stripTop = r.controls.y + (r.controls.height - stripH) / 2;
    r.rootStrip = Rect::ltrb(r.controls.x + kPad, stripTop,
                             std::max(r.controls.x + kPad, r.controls.right() - kPad),
                             stripTop + stripH);
    return r;
}

PreviewGlyph previewGlyph(const Rect& button) {
    PreviewGlyph g;
    if (button.empty()) return g;
    // Even height so the apex lands exactly on the button's horizontal centre line rather
    // than a half-pixel off it.
    int h = std::min({kPreviewGlyphMaxH, button.height - 2 * kPreviewGlyphPad,
                      button.width - 2 * kPreviewGlyphPad});
    h -= h % 2;
    if (h < kPreviewGlyphMinH) return g;
    const int w = std::max(2, (h * 7) / 8);  // ~equilateral: the classic transport triangle
    const int cx = button.x + button.width / 2;
    const int cy = button.y + button.height / 2;
    g.leftX = cx - w / 2;
    g.apexX = g.leftX + w;
    g.topY = cy - h / 2;
    g.bottomY = g.topY + h;
    g.apexY = cy;
    return g;
}

}  // namespace reasampler::instrument::ui
