// Tests para la logica de calculo del KPI card.
//
// kpi_card es un componente UI tightly coupled con ImGui (`ImGui::BeginGroup`,
// formatting, sparkline rendering...). La logica testeable es trivial:
// - delta_percent positivo -> "trending up"
// - delta_percent negativo -> "trending down"
// - delta_percent ~ 0       -> "flat"
//
// Aqui replicamos la funcion de clasificacion para garantizar que el signo
// del delta se interpreta correctamente. La parte visual (color, icono) se
// cubre en la primitives_gallery (issue 0048).

#define CATCH_CONFIG_MAIN
#include "catch_amalgamated.hpp"

#include <cmath>

namespace {

enum class Trend { Down, Flat, Up };

Trend classify_delta(float delta_percent, float flat_threshold = 0.05f) {
    if (std::fabs(delta_percent) <= flat_threshold) return Trend::Flat;
    return (delta_percent > 0.0f) ? Trend::Up : Trend::Down;
}

float pct_change(float current, float previous) {
    if (previous == 0.0f) return 0.0f;
    return 100.0f * (current - previous) / previous;
}

} // namespace

TEST_CASE("kpi_card: classify_delta positive -> Up", "[kpi_card]") {
    REQUIRE(classify_delta(0.5f)   == Trend::Up);
    REQUIRE(classify_delta(12.5f)  == Trend::Up);
    REQUIRE(classify_delta(100.0f) == Trend::Up);
}

TEST_CASE("kpi_card: classify_delta negative -> Down", "[kpi_card]") {
    REQUIRE(classify_delta(-0.5f)   == Trend::Down);
    REQUIRE(classify_delta(-15.0f)  == Trend::Down);
    REQUIRE(classify_delta(-100.0f) == Trend::Down);
}

TEST_CASE("kpi_card: classify_delta near zero -> Flat", "[kpi_card]") {
    REQUIRE(classify_delta(0.0f)    == Trend::Flat);
    REQUIRE(classify_delta(0.01f)   == Trend::Flat);
    REQUIRE(classify_delta(-0.01f)  == Trend::Flat);
    REQUIRE(classify_delta(0.05f)   == Trend::Flat); // exactly threshold
}

TEST_CASE("kpi_card: pct_change basic deltas", "[kpi_card]") {
    REQUIRE(pct_change(110.0f, 100.0f) == Catch::Approx(10.0f));
    REQUIRE(pct_change(90.0f,  100.0f) == Catch::Approx(-10.0f));
    REQUIRE(pct_change(100.0f, 100.0f) == Catch::Approx(0.0f));
    REQUIRE(pct_change(200.0f, 100.0f) == Catch::Approx(100.0f));
}

TEST_CASE("kpi_card: pct_change with zero previous returns 0", "[kpi_card]") {
    // Definicion: cambio porcentual de 0 a X es indefinido, devolvemos 0.
    REQUIRE(pct_change(50.0f, 0.0f) == Catch::Approx(0.0f));
    REQUIRE(pct_change(0.0f,  0.0f) == Catch::Approx(0.0f));
}

TEST_CASE("kpi_card: pct_change handles negative values", "[kpi_card]") {
    // -10 -> -5: ((-5) - (-10)) / (-10) * 100 = 5 / -10 * 100 = -50%.
    REQUIRE(pct_change(-5.0f, -10.0f) == Catch::Approx(-50.0f));
}
