// param_slider.cpp — see param_slider.h. PURE control-surface geometry for the S12/S15/S16
// editor parameter panel. No host types; only the shared Rect + contains().

#include "param_slider.h"

#include <algorithm>

namespace reasampler::vst {

std::vector<ControlRow> layoutControls(const Rect& panel,
                                       const std::vector<ControlDesc>& controls) {
    std::vector<ControlRow> out;
    if (controls.empty() || panel.width() <= 0 || panel.height() <= 0) return out;
    out.reserve(controls.size());

    // The label column is clamped so a narrow panel still leaves a control column.
    const int labelW = (std::min)(kControlLabelWidth, (std::max)(0, panel.width() / 2));
    int rowTop = panel.top;
    for (const ControlDesc& d : controls) {
        ControlRow r;
        r.id = d.id;
        r.kind = d.kind;
        const int rowBottom = rowTop + kControlRowHeight;
        r.row = Rect{panel.left, rowTop, panel.right, rowBottom};
        r.label = Rect{panel.left, rowTop, panel.left + labelW, rowBottom};
        r.control = Rect{panel.left + labelW, rowTop, panel.right, rowBottom};
        out.push_back(r);
        rowTop = rowBottom + kControlRowGap;
    }
    return out;
}

Rect toggleSegmentRect(const Rect& control, int seg) {
    if (seg < 0 || seg >= kToggleSegments) return Rect{};
    const int w = control.width();
    if (w <= 0 || control.height() <= 0) return Rect{};
    const int segW = w / kToggleSegments;
    const int left = control.left + seg * segW;
    // The last segment absorbs the width remainder so the segments tile the whole control.
    const int right = (seg == kToggleSegments - 1) ? control.right : left + segW;
    return Rect{left, control.top, right, control.bottom};
}

int toggleSegmentHitTest(const Rect& control, int x, int y) {
    if (!contains(control, x, y)) return -1;
    for (int seg = 0; seg < kToggleSegments; ++seg) {
        if (contains(toggleSegmentRect(control, seg), x, y)) return seg;
    }
    return -1;
}

Rect sliderTrackRect(const Rect& control) {
    // Inset a half-handle at each end so the handle stays fully inside the control at value
    // 0 and 1. The handle CENTER ranges across [track.left, track.right].
    const int half = kSliderHandleWidth / 2;
    if (control.width() <= kSliderHandleWidth || control.height() <= 0) return Rect{};
    return Rect{control.left + half, control.top, control.right - half, control.bottom};
}

Rect sliderHandleRect(const Rect& control, double value) {
    const Rect track = sliderTrackRect(control);
    if (track.width() <= 0) return Rect{};
    if (value < 0.0) value = 0.0;
    if (value > 1.0) value = 1.0;
    const int span = track.width();  // handle-center movable span
    const int centerX = track.left + static_cast<int>(value * span + 0.5);
    const int half = kSliderHandleWidth / 2;
    return Rect{centerX - half, control.top, centerX - half + kSliderHandleWidth,
                control.bottom};
}

double valueAtPoint(const Rect& control, int x) {
    const Rect track = sliderTrackRect(control);
    const int span = track.width();
    if (span <= 0) return 0.0;
    if (x <= track.left) return 0.0;
    if (x >= track.right) return 1.0;
    return static_cast<double>(x - track.left) / static_cast<double>(span);
}

int controlAtPoint(const std::vector<ControlRow>& rows, int x, int y) {
    for (const ControlRow& r : rows) {
        if (r.kind == ControlKind::Toggle) {
            if (contains(r.control, x, y)) return r.id;
        } else {  // Slider — the interactive area is the track
            if (contains(sliderTrackRect(r.control), x, y)) return r.id;
        }
    }
    return -1;
}

}  // namespace reasampler::vst
