// render_window.cpp — see the header.

#include "core/capture/render_window.h"

#include <cmath>

namespace reasampler::capture {

namespace {

// Round-to-nearest: the convention THIS module measures a window by, so a mid-frame
// position maps to the closer frame boundary rather than always down. Not a claim
// about how any renderer resolves that position -- see the header's caveat.
long long frameIndexAt(double seconds, int sampleRate) {
    return std::llround(seconds * static_cast<double>(sampleRate));
}

// See the header for why whole milliseconds get a tolerance and why it is this small.
double floorToMilliseconds(double seconds) {
    const double ms = seconds * 1000.0;
    if (isOnMillisecondGrid(seconds)) return std::nearbyint(ms) / 1000.0;
    return std::floor(ms) / 1000.0;
}

}  // namespace

long long frameCountFor(double startSeconds, double endSeconds, int sampleRate) {
    if (sampleRate <= 0) return 0;
    if (!(endSeconds > startSeconds)) return 0;
    const long long frames =
        frameIndexAt(endSeconds, sampleRate) - frameIndexAt(startSeconds, sampleRate);
    return frames > 0 ? frames : 0;
}

bool renderHonoredBounds(long long expectedFrames, long long actualFrames) {
    const long long delta = actualFrames > expectedFrames
        ? actualFrames - expectedFrames
        : expectedFrames - actualFrames;
    return delta <= 1;
}

bool itemExtentPrintsWindow(double reqStart, double reqEnd,
                            double itemStart, double itemEnd,
                            int sampleRate) {
    if (sampleRate <= 0)
        return reqStart == itemStart && reqEnd == itemEnd;
    return frameIndexAt(reqStart, sampleRate) == frameIndexAt(itemStart, sampleRate)
        && frameIndexAt(reqEnd,   sampleRate) == frameIndexAt(itemEnd,   sampleRate);
}

bool isOnMillisecondGrid(double seconds) {
    const double ms = seconds * 1000.0;
    return std::fabs(ms - std::nearbyint(ms)) < 1e-6;
}

long long msFlooredEndFrameCount(double startSeconds, double endSeconds,
                                 int sampleRate) {
    return frameCountFor(startSeconds, floorToMilliseconds(endSeconds), sampleRate);
}

}  // namespace reasampler::capture
