#include <doctest/doctest.h>

#include "fgc/TestReport.h"

using namespace fgc;

namespace {
TestReport makeReport() {
    TestReport r;
    r.ts_ms = 1719312345678LL;
    r.profile = "standard";
    r.host = "towerpc";
    r.fw = "fgc-1.2.3";
    TestSection s;
    s.id = "homing";
    s.title = "homing reproducibility";
    s.ran = true;
    s.duration_ms = 1234;
    TestMetric m1;
    m1.name = "yaw_lim_neg_spread"; m1.value = 12; m1.unit = "counts";
    m1.has_threshold = true; m1.threshold = 80; m1.pass = true;
    s.metrics.push_back(m1);
    TestMetric m2;
    m2.name = "home_ms_mean"; m2.value = 8200.5; m2.unit = "ms"; m2.pass = true;
    s.metrics.push_back(m2);
    s.pass = true;
    r.sections.push_back(s);
    r.all_pass = true;
    return r;
}
}  // namespace

TEST_CASE("formatTestReport round-trips through parseTestReport") {
    TestReport r = makeReport();
    std::string text = formatTestReport(r);
    TestReport back = parseTestReport(text);

    CHECK(back.ts_ms == r.ts_ms);
    CHECK(back.profile == "standard");
    CHECK(back.host == "towerpc");
    CHECK(back.fw == "fgc-1.2.3");
    CHECK(back.all_pass == true);
    REQUIRE(back.sections.size() == 1);
    CHECK(back.sections[0].id == "homing");

    const TestMetric* m = back.find("homing", "yaw_lim_neg_spread");
    REQUIRE(m != nullptr);
    CHECK(m->value == doctest::Approx(12));
    CHECK(m->unit == "counts");
    const TestMetric* m2 = back.find("homing", "home_ms_mean");
    REQUIRE(m2 != nullptr);
    CHECK(m2->value == doctest::Approx(8200.5));
}

TEST_CASE("applyComparison computes drift and flags regressions") {
    TestReport baseline = makeReport();              // yaw_lim_neg_spread = 12
    TestReport prev = makeReport();
    prev.sections[0].metrics[0].value = 13;

    TestReport cur = makeReport();
    cur.sections[0].metrics[0].value = 18;           // +50% vs baseline (12)

    applyComparison(cur, &baseline, &prev, /*warn_pct=*/15, /*gates=*/true);

    const TestMetric* m = cur.find("homing", "yaw_lim_neg_spread");
    REQUIRE(m != nullptr);
    CHECK(m->has_baseline);
    CHECK(m->baseline == doctest::Approx(12));
    CHECK(m->has_prev);
    CHECK(m->prev == doctest::Approx(13));
    CHECK(m->drift_pct == doctest::Approx(50.0));
    CHECK(m->drift_flag == true);
    CHECK(m->pass == false);          // drift gate trips the metric
    CHECK(cur.sections[0].pass == false);
    CHECK(cur.all_pass == false);
}

TEST_CASE("applyComparison: improvement (lower is better) does not flag") {
    TestReport baseline = makeReport();              // 12
    TestReport cur = makeReport();
    cur.sections[0].metrics[0].value = 6;            // -50%, an improvement

    applyComparison(cur, &baseline, nullptr, 15, true);
    const TestMetric* m = cur.find("homing", "yaw_lim_neg_spread");
    REQUIRE(m != nullptr);
    CHECK(m->drift_flag == false);
    CHECK(m->pass == true);
}
