#pragma once

#include <string>
#include <vector>

namespace fgc {

// Structured result of a hardware self-test run (the `test` command). Pure data
// + I/O-free format/parse/compare, mirroring DiagParser so it unit-tests in
// fgc_core. formatTestReport() emits a plain-text report that is also stable
// enough for parseTestReport() to read back for baseline/previous comparison.

struct TestMetric {
    std::string name;                 // e.g. "yaw_lim_neg_spread"
    double      value = 0.0;
    std::string unit;                 // e.g. "counts", "ms", "deg/min" ("" = none)
    bool        lower_is_better = true;

    bool        has_threshold = false;
    double      threshold = 0.0;
    bool        pass = true;          // verdict for this metric (abs + optional drift)

    // Filled by applyComparison() against the baseline / previous report.
    bool        has_baseline = false;
    double      baseline = 0.0;
    bool        has_prev = false;
    double      prev = 0.0;
    double      drift_pct = 0.0;      // vs baseline (or prev if no baseline)
    bool        drift_flag = false;   // drift exceeded the profile's warn threshold
};

struct TestSection {
    std::string             id;       // "homing", "encoder", "imu_health", ...
    std::string             title;    // human label
    bool                    ran = false;
    bool                    pass = true;
    double                  duration_ms = 0.0;
    std::vector<TestMetric> metrics;
    std::vector<std::string> notes;   // free-form lines (e.g. "LP unavailable; ST-sampled")
};

struct TestReport {
    long long                ts_ms = 0;
    std::string              profile;
    std::string              host;
    std::string              fw;
    bool                     all_pass = true;
    std::vector<TestSection> sections;

    // Find a metric by section id + metric name (used by applyComparison/tests).
    const TestMetric* find(const std::string& section_id, const std::string& metric) const;
};

// Plain-text, human-readable AND round-trippable report.
std::string formatTestReport(const TestReport& r);

// Re-read a report previously produced by formatTestReport(). Only the fields
// needed for comparison are recovered (section id, metric name + value);
// derived columns (base/prev/drift) are recomputed by applyComparison().
TestReport parseTestReport(const std::string& text);

// Fill baseline/prev/drift on `cur` from prior reports (either may be null).
// `drift_warn_pct` flags a metric when |drift| exceeds it; if `drift_gates_pass`
// a flagged metric also fails (and its section + the report roll up to FAIL).
void applyComparison(TestReport& cur, const TestReport* baseline, const TestReport* prev,
                     double drift_warn_pct, bool drift_gates_pass);

}  // namespace fgc
