// keyboard_strip.h — piano-keyboard geometry for the editor's root strip: per-class key
// rects, hit-test, the root marker, and the note name a hovered key reports.
//
// See src/core/instrument/CLAUDE.md for the uniform-width-vs-edge-to-edge-tiling tradeoff.

#pragma once

#include <string>

#include "core/instrument/ui/editor_geometry.h"  // Rect, contains

namespace reasampler::instrument::ui {

// Named distinctly from embed_strip's kEmbedKeyCount (same value) so the two strips
// stay independent.
inline constexpr int kStripKeyCount = 128;

// Naturals in MIDI 0..127 (C-1 .. G9): ten full octaves of seven, plus C D E F G.
inline constexpr int kStripWhiteKeyCount = 75;

struct StripLayout {
    Rect band;   // the surface handed in, edge to edge (no src/ consumer; kept as the tests'
                 // reference bound instead of recomputing Rect::ltrb(0, 0, w, h) at each call site)
    Rect keys;   // the tiled key area, kStripWhiteKeyCount * whiteWidth, centred in band
    int whiteWidth = 0;
    int blackWidth = 0;
    int blackHeight = 0;  // black keys are short; below them the white key answers
};

// Divide a (w x h) strip area into its key geometry. Pure. A band too narrow for one pixel
// per white key yields empty `keys` — nothing draws and nothing hit-tests.
StripLayout layoutStrip(int w, int h);

// True when `note` (clamped to [0,127]) is a natural (white) key in 12-tone equal
// temperament; false for an accidental (black) key.
bool isNaturalKey(int note);

// Naturals strictly below `note`. For a white key that is its own ordinal; for a black key
// it is the white-key boundary the accidental straddles.
int whiteIndexOf(int note);

// Rect of a single key, clamped to [0,127]. Whites are full band height and whiteWidth
// wide; blacks are blackHeight tall and blackWidth wide, centred on their boundary.
Rect keyRect(const StripLayout& layout, int note);

// Root-marker rect; equivalent to keyRect(layout, rootNote) but named so the intent reads
// at the call site.
Rect rootMarkerRect(const StripLayout& layout, int rootNote);

// MIDI note a point (x, y) lands on, or -1 outside the tiled keys. A black key wins inside
// its own short zone; anywhere else the white key beneath answers.
int keyAtPoint(const StripLayout& layout, int x, int y);

// The note a live drag resolves to: keyAtPoint with the point clamped into the key area, so
// a drag that wanders off the strip keeps tracking rather than dropping the edit. -1 only
// when there is no key area at all.
int resolveDragNote(const StripLayout& layout, int x, int y);

// DAW convention (the one REAPER uses): MIDI 60 is C4, so MIDI 0 is C-1.
std::string noteName(int note);

}  // namespace reasampler::instrument::ui
