// Tests para la logica numerica del bar_chart (computo de limites de eje Y,
// escala, etc.).
//
// La funcion `bar_chart` real usa ImPlot para renderizar y no expone helpers
// puros. Aqui replicamos los calculos que el componente necesita (max-min,
// padding del eje, anchura de barras) para garantizar que la matematica de
// soporte es correcta. Los tests visuales viven en primitives_gallery (0048).

#define CATCH_CONFIG_MAIN
#include "catch_amalgamated.hpp"

#include <algorithm>
#include <vector>

namespace {

struct YRange { double lo; double hi; };

YRange compute_y_range(const double* values, int count, double pad = 0.1) {
    if (count <= 0) return {0.0, 1.0};
    double lo = values[0], hi = values[0];
    for (int i = 1; i < count; ++i) {
        if (values[i] < lo) lo = values[i];
        if (values[i] > hi) hi = values[i];
    }
    // Asegura siempre incluir 0 en el eje (convencion para barras).
    if (lo > 0.0) lo = 0.0;
    if (hi < 0.0) hi = 0.0;
    double span = hi - lo;
    if (span == 0.0) span = 1.0;
    return {lo - span * pad * (lo < 0.0 ? 1.0 : 0.0),
            hi + span * pad};
}

double clamp_bar_width(double w) {
    if (w < 0.05) return 0.05;
    if (w > 1.0)  return 1.0;
    return w;
}

} // namespace

TEST_CASE("bar_chart: y_range covers all positive values", "[bar_chart]") {
    double v[] = {1.0, 2.0, 3.0, 4.0, 5.0};
    auto r = compute_y_range(v, 5);
    REQUIRE(r.lo == Catch::Approx(0.0));
    REQUIRE(r.hi >= 5.0);
}

TEST_CASE("bar_chart: y_range includes zero baseline", "[bar_chart]") {
    double v[] = {3.0, 5.0, 7.0};
    auto r = compute_y_range(v, 3);
    REQUIRE(r.lo == Catch::Approx(0.0));
}

TEST_CASE("bar_chart: y_range with negatives extends below zero", "[bar_chart]") {
    double v[] = {-2.0, 1.0, 3.0};
    auto r = compute_y_range(v, 3);
    REQUIRE(r.lo <= -2.0);
    REQUIRE(r.hi >= 3.0);
}

TEST_CASE("bar_chart: y_range with empty data is sane default", "[bar_chart]") {
    auto r = compute_y_range(nullptr, 0);
    REQUIRE(r.lo < r.hi);
}

TEST_CASE("bar_chart: y_range with single value still has span", "[bar_chart]") {
    double v[] = {7.0};
    auto r = compute_y_range(v, 1);
    REQUIRE(r.hi > r.lo);
}

TEST_CASE("bar_chart: clamp_bar_width clamps to [0.05, 1.0]", "[bar_chart]") {
    REQUIRE(clamp_bar_width(0.001) == Catch::Approx(0.05));
    REQUIRE(clamp_bar_width(0.5)   == Catch::Approx(0.5));
    REQUIRE(clamp_bar_width(0.67)  == Catch::Approx(0.67));
    REQUIRE(clamp_bar_width(2.0)   == Catch::Approx(1.0));
}
