#pragma once
// card_meta — pure formatting for the L7 decorative card metadata overlay. Each bank
// card overlays capture length as bars.beats.subdivisions (bottom-LEFT, musical) and
// seconds.milliseconds (bottom-RIGHT, wall-clock). Both read-outs are DECORATIVE and
// non-interactive; the bank_panel draws them via the L1 kit. The formatting itself is
// pure string work over the sample's stamped tempo + meter + length, so it is
// unit-tested outside the DAW (CLAUDE.md §load-bearing split).
//
// PURE MODULE: NO REAPER types, NO SWELL, NO LICE, NO vendor/ includes. Standard
// library only. Mirror of tooltip's prefix-strip helper.

#include <string>

namespace reasampler {

// The musical length inputs, taken straight off a Sample (L7 F1 capture-time stamp):
//   lengthSeconds — captured length in wall-clock seconds (>= 0).
//   tempoBpm      — project tempo (BPM) at capture (Sample.captureTempo); 0 = unknown.
//   timeSigNum    — meter numerator at capture (Sample.captureTimeSigNum); 0 = unstamped.
//   timeSigDenom  — meter denominator at capture (Sample.captureTimeSigDenom); 0 = unstamped.
struct MusicalLength {
    double lengthSeconds = 0.0;
    double tempoBpm      = 0.0;
    int    timeSigNum    = 0;
    int    timeSigDenom  = 0;
};

// bars.beats.subdivisions from a capture-time tempo + meter stamp (musical read-out).
//
// Derivation: one quarter-note lasts 60 / tempo seconds; a beat in this meter lasts
// (4 / timeSigDenom) quarter-notes; a bar holds timeSigNum beats. From lengthSeconds we
// get total beats, split into whole bars (÷ timeSigNum) + whole leftover beats + a
// subdivision remainder scaled to 1..N of the next beat. The output is 1-BASED and
// zero-padded to two subdivision digits: "1.1.00" is exactly one bar-start (a
// zero-length or bar-aligned capture), "2.3.50" is 1 bar + 2 beats + half a beat.
//
// Contract / edge cases (all tested):
//   * UNSTAMPED meter (timeSigNum <= 0 || timeSigDenom <= 0) OR unknown tempo
//     (tempoBpm <= 0): returns "" — no musical read-out is derivable (the caller keeps
//     the s.ms read-out). This is the pre-L7-sample fallback (blank musical read-out).
//   * zero length: "1.1.00" (bar 1, beat 1, no subdivision) — the musical origin.
//   * exact bar boundary: the beat rolls to 1 and the bar increments (never "1.5.00"
//     in 4/4 — that reads as "2.1.00").
//   * long captures: bars grow without cap ("129.1.00" is fine).
// The subdivision is 0..99 (hundredths of a beat), floored — a display quantum, not a
// tick-accurate PPQ (the model refuses to invent PPQ; this is a decorative read-out).
std::string formatBarsBeats(const MusicalLength& m);

// seconds.milliseconds from a wall-clock length (always derivable, meter-independent).
//   * "S.mmm" — integer seconds, a dot, zero-padded 3-digit milliseconds (rounded to nearest ms).
//     e.g. 0.0 -> "0.000", 1.5 -> "1.500", 62.037 -> "62.037".
//   * negative length is clamped to "0.000" (a length is never negative; defensive).
std::string formatSecondsMs(double lengthSeconds);

} // namespace reasampler
