#pragma once
// data_types.hpp
// 所有消息数据结构定义，JSON key 与 proto 字段名及 gateway_codec.hpp 完全一致。
// 使用 nlohmann/json ADL 钩子（from_json / to_json）实现序列化。

#include <cstdint>
#include <string>
#include <vector>
#include <variant>
#include <nlohmann/json.hpp>

namespace vaw
{

// ===========================================================================
// 枚举
// ===========================================================================

enum class ErrorCode : uint32_t {
    UNSPECIFIED               = 0,
    OK                        = 1,
    INVALID_ARGUMENT          = 2,
    INVALID_STATE             = 3,
    VEHICLE_BUSY              = 4,
    NOT_READY                 = 5,
    TIMEOUT                   = 6,
    NETWORK_LOSS              = 7,
    SAFETY_TRIGGERED          = 8,
    HARDWARE_FAULT            = 9,
    FILE_NOT_FOUND            = 10,
    CHECKSUM_MISMATCH         = 11,
    INTERNAL_ERROR            = 12,
    UNSUPPORTED_CAPABILITY    = 13,
    RESOURCE_LOCKED           = 14,
    MANUAL_CONFIRM_REQUIRED   = 15,
    APPROVAL_REQUIRED         = 16,
    VALIDATION_FAILED         = 17,
    ROLLBACK_REQUIRED         = 18,
    DATA_QUALITY_INSUFFICIENT = 19,
};

enum class ChassisMotionPrimitiveType : uint32_t {
    UNSPECIFIED          = 0,
    STRAIGHT_LINE        = 1,
    ARC                  = 2,
    IN_PLACE_ROTATION    = 3,
    STEERING_SWEEP       = 4,
    LATERAL_TRANSLATION  = 5,
    DIAGONAL_MOTION      = 6,
    MODULE_ALIGNMENT     = 7,
    COORDINATED_STEERING = 8,
};

enum class ControlEvaluationTaskType : uint32_t {
    UNSPECIFIED               = 0,
    TRAJECTORY_TRACKING       = 1,
    VELOCITY_STEP             = 2,
    ACCELERATION_DECELERATION = 3,
    STOP_ACCURACY             = 4,
};

// ===========================================================================
// 公共类型
// ===========================================================================

struct RequestHeader {
    std::string session_id;
    std::string task_id;
    std::string vehicle_id;
    std::string request_id;
    int64_t     client_send_timestamp_us{0};
    std::string operator_id;
    std::string workshop_host;
};

inline void from_json(const nlohmann::json& j, RequestHeader& h)
{
    h.session_id               = j.value("session_id",               std::string{});
    h.task_id                  = j.value("task_id",                  std::string{});
    h.vehicle_id               = j.value("vehicle_id",               std::string{});
    h.request_id               = j.value("request_id",               std::string{});
    h.client_send_timestamp_us = j.value("client_send_timestamp_us", int64_t{0});
    h.operator_id              = j.value("operator_id",              std::string{});
    h.workshop_host            = j.value("workshop_host",            std::string{});
}

inline void to_json(nlohmann::json& j, const RequestHeader& h)
{
    j = {
        {"session_id",               h.session_id},
        {"task_id",                  h.task_id},
        {"vehicle_id",               h.vehicle_id},
        {"request_id",               h.request_id},
        {"client_send_timestamp_us", h.client_send_timestamp_us},
        {"operator_id",              h.operator_id},
        {"workshop_host",            h.workshop_host},
    };
}

struct FileReference {
    std::string file_name;
    std::string file_uri;
    int64_t     size_bytes{0};
    std::string description;
};

inline void from_json(const nlohmann::json& j, FileReference& r)
{
    r.file_name   = j.value("file_name",   std::string{});
    r.file_uri    = j.value("file_uri",    std::string{});
    r.size_bytes  = j.value("size_bytes",  int64_t{0});
    r.description = j.value("description", std::string{});
}

inline void to_json(nlohmann::json& j, const FileReference& r)
{
    j = {
        {"file_name",   r.file_name},
        {"file_uri",    r.file_uri},
        {"size_bytes",  r.size_bytes},
        {"description", r.description},
    };
}

// ===========================================================================
// 底盘命令原语
// ===========================================================================

struct StraightLineCommand {
    double target_speed_ms{0.0};
    double target_distance_m{0.0};
    bool   reverse{false};
};
inline void from_json(const nlohmann::json& j, StraightLineCommand& c) {
    c.target_speed_ms    = j.value("target_speed_ms",    0.0);
    c.target_distance_m  = j.value("target_distance_m",  0.0);
    c.reverse            = j.value("reverse",            false);
}
inline void to_json(nlohmann::json& j, const StraightLineCommand& c) {
    j = {{"target_speed_ms", c.target_speed_ms},
         {"target_distance_m", c.target_distance_m},
         {"reverse", c.reverse}};
}

struct ArcCommand {
    double target_speed_ms{0.0};
    double radius_m{0.0};
    double sweep_angle_deg{0.0};
    bool   clockwise{false};
};
inline void from_json(const nlohmann::json& j, ArcCommand& c) {
    c.target_speed_ms  = j.value("target_speed_ms",  0.0);
    c.radius_m         = j.value("radius_m",         0.0);
    c.sweep_angle_deg  = j.value("sweep_angle_deg",  0.0);
    c.clockwise        = j.value("clockwise",        false);
}
inline void to_json(nlohmann::json& j, const ArcCommand& c) {
    j = {{"target_speed_ms", c.target_speed_ms},
         {"radius_m", c.radius_m},
         {"sweep_angle_deg", c.sweep_angle_deg},
         {"clockwise", c.clockwise}};
}

struct InPlaceRotationCommand {
    double target_yaw_deg{0.0};
    double target_angular_vel_deg_s{0.0};
};
inline void from_json(const nlohmann::json& j, InPlaceRotationCommand& c) {
    c.target_yaw_deg           = j.value("target_yaw_deg",           0.0);
    c.target_angular_vel_deg_s = j.value("target_angular_vel_deg_s", 0.0);
}
inline void to_json(nlohmann::json& j, const InPlaceRotationCommand& c) {
    j = {{"target_yaw_deg", c.target_yaw_deg},
         {"target_angular_vel_deg_s", c.target_angular_vel_deg_s}};
}

struct SteeringSweepCommand {
    double target_angle_deg{0.0};
    double sweep_amplitude_deg{0.0};
    double sweep_frequency_hz{0.0};
    double duration_sec{0.0};
};
inline void from_json(const nlohmann::json& j, SteeringSweepCommand& c) {
    c.target_angle_deg    = j.value("target_angle_deg",    0.0);
    c.sweep_amplitude_deg = j.value("sweep_amplitude_deg", 0.0);
    c.sweep_frequency_hz  = j.value("sweep_frequency_hz",  0.0);
    c.duration_sec        = j.value("duration_sec",        0.0);
}
inline void to_json(nlohmann::json& j, const SteeringSweepCommand& c) {
    j = {{"target_angle_deg", c.target_angle_deg},
         {"sweep_amplitude_deg", c.sweep_amplitude_deg},
         {"sweep_frequency_hz", c.sweep_frequency_hz},
         {"duration_sec", c.duration_sec}};
}

struct LateralTranslationCommand {
    double target_speed_ms{0.0};
    double target_distance_m{0.0};
    bool   move_left{false};
};
inline void from_json(const nlohmann::json& j, LateralTranslationCommand& c) {
    c.target_speed_ms   = j.value("target_speed_ms",   0.0);
    c.target_distance_m = j.value("target_distance_m", 0.0);
    c.move_left         = j.value("move_left",         false);
}
inline void to_json(nlohmann::json& j, const LateralTranslationCommand& c) {
    j = {{"target_speed_ms", c.target_speed_ms},
         {"target_distance_m", c.target_distance_m},
         {"move_left", c.move_left}};
}

struct DiagonalMotionCommand {
    double target_speed_ms{0.0};
    double target_distance_m{0.0};
    double heading_deg{0.0};
};
inline void from_json(const nlohmann::json& j, DiagonalMotionCommand& c) {
    c.target_speed_ms   = j.value("target_speed_ms",   0.0);
    c.target_distance_m = j.value("target_distance_m", 0.0);
    c.heading_deg       = j.value("heading_deg",       0.0);
}
inline void to_json(nlohmann::json& j, const DiagonalMotionCommand& c) {
    j = {{"target_speed_ms", c.target_speed_ms},
         {"target_distance_m", c.target_distance_m},
         {"heading_deg", c.heading_deg}};
}

struct ModuleAlignmentCheckCommand {
    std::vector<std::string> module_ids;
    double target_zero_deg{0.0};
    double tolerance_deg{0.0};
};
inline void from_json(const nlohmann::json& j, ModuleAlignmentCheckCommand& c) {
    if (j.contains("module_ids") && j["module_ids"].is_array())
        c.module_ids = j["module_ids"].get<std::vector<std::string>>();
    c.target_zero_deg = j.value("target_zero_deg", 0.0);
    c.tolerance_deg   = j.value("tolerance_deg",   0.0);
}
inline void to_json(nlohmann::json& j, const ModuleAlignmentCheckCommand& c) {
    j = {{"module_ids", c.module_ids},
         {"target_zero_deg", c.target_zero_deg},
         {"tolerance_deg", c.tolerance_deg}};
}

struct CoordinatedSteeringCommand {
    std::vector<std::string> module_ids;
    double target_angle_deg{0.0};
    double hold_time_sec{0.0};
};
inline void from_json(const nlohmann::json& j, CoordinatedSteeringCommand& c) {
    if (j.contains("module_ids") && j["module_ids"].is_array())
        c.module_ids = j["module_ids"].get<std::vector<std::string>>();
    c.target_angle_deg = j.value("target_angle_deg", 0.0);
    c.hold_time_sec    = j.value("hold_time_sec",    0.0);
}
inline void to_json(nlohmann::json& j, const CoordinatedSteeringCommand& c) {
    j = {{"module_ids", c.module_ids},
         {"target_angle_deg", c.target_angle_deg},
         {"hold_time_sec", c.hold_time_sec}};
}

// ===========================================================================
// 底盘请求聚合
// ===========================================================================

// primitive 字段用 variant，index 对应 ChassisMotionPrimitiveType 枚举值
using ChassisMotionPrimitive = std::variant<
    std::monostate,            // UNSPECIFIED (0)
    StraightLineCommand,       // 1
    ArcCommand,                // 2
    InPlaceRotationCommand,    // 3
    SteeringSweepCommand,      // 4
    LateralTranslationCommand, // 5
    DiagonalMotionCommand,     // 6
    ModuleAlignmentCheckCommand, // 7
    CoordinatedSteeringCommand   // 8
>;

struct MotionPrimitiveRequest {
    RequestHeader            header;
    std::string              test_case_id;
    uint32_t                 task_purpose{0};          // TaskPurpose enum value
    ChassisMotionPrimitiveType selected_primitive{ChassisMotionPrimitiveType::UNSPECIFIED};
    ChassisMotionPrimitive   primitive;                // 对应 selected_primitive 的具体命令
    bool                     brake_when_finished{false};
    double                   timeout_sec{0.0};
    std::string              source_iteration_id;
};

// 从 JSON 解析 MotionPrimitiveRequest（对应 gateway_codec.hpp encode_motion_primitive_request）
inline void from_json(const nlohmann::json& j, MotionPrimitiveRequest& r)
{
    if (j.contains("header")) r.header = j["header"].get<RequestHeader>();
    r.test_case_id        = j.value("test_case_id",        std::string{});
    r.task_purpose        = j.value("task_purpose",        uint32_t{0});
    r.selected_primitive  = static_cast<ChassisMotionPrimitiveType>(j.value("selected_primitive", uint32_t{0}));
    r.brake_when_finished = j.value("brake_when_finished", false);
    r.timeout_sec         = j.value("timeout_sec",         0.0);
    r.source_iteration_id = j.value("source_iteration_id", std::string{});

    switch (r.selected_primitive) {
        case ChassisMotionPrimitiveType::STRAIGHT_LINE:
            if (j.contains("straight_line"))
                r.primitive = j["straight_line"].get<StraightLineCommand>();
            break;
        case ChassisMotionPrimitiveType::ARC:
            if (j.contains("arc"))
                r.primitive = j["arc"].get<ArcCommand>();
            break;
        case ChassisMotionPrimitiveType::IN_PLACE_ROTATION:
            if (j.contains("in_place_rotation"))
                r.primitive = j["in_place_rotation"].get<InPlaceRotationCommand>();
            break;
        case ChassisMotionPrimitiveType::STEERING_SWEEP:
            if (j.contains("steering_sweep"))
                r.primitive = j["steering_sweep"].get<SteeringSweepCommand>();
            break;
        case ChassisMotionPrimitiveType::LATERAL_TRANSLATION:
            if (j.contains("lateral_translation"))
                r.primitive = j["lateral_translation"].get<LateralTranslationCommand>();
            break;
        case ChassisMotionPrimitiveType::DIAGONAL_MOTION:
            if (j.contains("diagonal_motion"))
                r.primitive = j["diagonal_motion"].get<DiagonalMotionCommand>();
            break;
        case ChassisMotionPrimitiveType::MODULE_ALIGNMENT:
            if (j.contains("module_alignment"))
                r.primitive = j["module_alignment"].get<ModuleAlignmentCheckCommand>();
            break;
        case ChassisMotionPrimitiveType::COORDINATED_STEERING:
            if (j.contains("coordinated_steering"))
                r.primitive = j["coordinated_steering"].get<CoordinatedSteeringCommand>();
            break;
        default:
            r.primitive = std::monostate{};
            break;
    }
}

// ===========================================================================
// 底盘响应类型
// ===========================================================================

struct ChassisReadinessResponse {
    bool        success{false};
    ErrorCode   error_code{ErrorCode::OK};
    std::string message;
    bool        agent_ready{false};
    bool        chassis_driver_online{false};
    bool        motion_control_ready{false};
    bool        estop_released{false};
    bool        vehicle_safe_to_move{false};
    bool        telemetry_available{false};
    int64_t     checked_timestamp_us{0};
};

inline void to_json(nlohmann::json& j, const ChassisReadinessResponse& r)
{
    j = {
        {"success",               r.success},
        {"error_code",            {"code", static_cast<uint32_t>(r.error_code)}},
        {"message",               r.message},
        {"agent_ready",           r.agent_ready},
        {"chassis_driver_online", r.chassis_driver_online},
        {"motion_control_ready",  r.motion_control_ready},
        {"estop_released",        r.estop_released},
        {"vehicle_safe_to_move",  r.vehicle_safe_to_move},
        {"telemetry_available",   r.telemetry_available},
        {"checked_timestamp_us",  r.checked_timestamp_us},
    };
}

struct ChassisValidationSummary {
    double straight_line_error_m{0.0};
    double heading_error_deg{0.0};
    double arc_radius_error_m{0.0};
    double rotation_error_deg{0.0};
    double repeatability_error_m{0.0};
    double curvature_error{0.0};
    double module_consistency_error{0.0};
    bool   auto_acceptance_passed{false};
};

inline void to_json(nlohmann::json& j, const ChassisValidationSummary& s)
{
    j = {
        {"straight_line_error_m",     s.straight_line_error_m},
        {"heading_error_deg",          s.heading_error_deg},
        {"arc_radius_error_m",         s.arc_radius_error_m},
        {"rotation_error_deg",         s.rotation_error_deg},
        {"repeatability_error_m",      s.repeatability_error_m},
        {"curvature_error",            s.curvature_error},
        {"module_consistency_error",   s.module_consistency_error},
        {"auto_acceptance_passed",     s.auto_acceptance_passed},
    };
}

struct ChassisJobResult {
    bool                     success{false};
    ErrorCode                error_code{ErrorCode::OK};
    std::string              message;
    std::string              job_id;
    bool                     data_quality_passed{false};
    bool                     suitable_for_commit{false};
    std::string              recommended_parameter_version;
    double                   estimated_straight_line_bias{0.0};
    ChassisValidationSummary validation_summary;
    std::vector<FileReference> artifacts;
};

inline void to_json(nlohmann::json& j, const ChassisJobResult& r)
{
    j = {
        {"success",                        r.success},
        {"error_code",                     {"code", static_cast<uint32_t>(r.error_code)}},
        {"message",                        r.message},
        {"job_id",                         r.job_id},
        {"data_quality_passed",            r.data_quality_passed},
        {"suitable_for_commit",            r.suitable_for_commit},
        {"recommended_parameter_version",  r.recommended_parameter_version},
        {"estimated_straight_line_bias",   r.estimated_straight_line_bias},
        {"validation_summary",             r.validation_summary},
        {"artifacts",                      r.artifacts},
    };
}

// ===========================================================================
// 运控命令类型
// ===========================================================================

struct TrajectoryPoint {
    double x_m{0.0};
    double y_m{0.0};
    double yaw_rad{0.0};
    double target_speed_ms{0.0};
};
inline void from_json(const nlohmann::json& j, TrajectoryPoint& p) {
    p.x_m            = j.value("x_m",            0.0);
    p.y_m            = j.value("y_m",            0.0);
    p.yaw_rad        = j.value("yaw_rad",        0.0);
    p.target_speed_ms = j.value("target_speed_ms", 0.0);
}

struct TrajectoryTrackingTask {
    std::vector<TrajectoryPoint> path;
    bool   stop_at_end{false};
    double timeout_sec{0.0};
    std::string required_external_pose_source_id;
    double max_external_pose_age_ms{0.0};
    double min_external_pose_quality_score{0.0};
    std::string trajectory_id;
    uint32_t segment_index{0};
    uint32_t total_segments{0};
    bool is_final_segment{false};
};
inline void from_json(const nlohmann::json& j, TrajectoryTrackingTask& t) {
    if (j.contains("path") && j["path"].is_array())
        t.path = j["path"].get<std::vector<TrajectoryPoint>>();
    t.stop_at_end = j.value("stop_at_end", false);
    t.timeout_sec = j.value("timeout_sec", 0.0);
    t.required_external_pose_source_id = j.value("required_external_pose_source_id", std::string{});
    t.max_external_pose_age_ms = j.value("max_external_pose_age_ms", 0.0);
    t.min_external_pose_quality_score = j.value("min_external_pose_quality_score", 0.0);
    t.trajectory_id = j.value("trajectory_id", std::string{});
    t.segment_index = j.value("segment_index", uint32_t{0});
    t.total_segments = j.value("total_segments", uint32_t{0});
    t.is_final_segment = j.value("is_final_segment", false);
}

struct VelocityStepTask {
    double target_velocity_ms{0.0};
    double hold_time_sec{0.0};
    double settle_before_step_sec{0.0};
};
inline void from_json(const nlohmann::json& j, VelocityStepTask& t) {
    t.target_velocity_ms      = j.value("target_velocity_ms",      0.0);
    t.hold_time_sec           = j.value("hold_time_sec",           0.0);
    t.settle_before_step_sec  = j.value("settle_before_step_sec",  0.0);
}

struct AccelerationDecelerationTask {
    double start_velocity_ms{0.0};
    double target_velocity_ms{0.0};
    double target_accel_ms2{0.0};
    double hold_time_sec{0.0};
};
inline void from_json(const nlohmann::json& j, AccelerationDecelerationTask& t) {
    t.start_velocity_ms  = j.value("start_velocity_ms",  0.0);
    t.target_velocity_ms = j.value("target_velocity_ms", 0.0);
    t.target_accel_ms2   = j.value("target_accel_ms2",   0.0);
    t.hold_time_sec      = j.value("hold_time_sec",      0.0);
}

struct StopAccuracyTask {
    double target_stop_x_m{0.0};
    double target_stop_y_m{0.0};
    double target_stop_yaw_rad{0.0};
    double timeout_sec{0.0};
};
inline void from_json(const nlohmann::json& j, StopAccuracyTask& t) {
    t.target_stop_x_m   = j.value("target_stop_x_m",   0.0);
    t.target_stop_y_m   = j.value("target_stop_y_m",   0.0);
    t.target_stop_yaw_rad = j.value("target_stop_yaw_rad", 0.0);
    t.timeout_sec       = j.value("timeout_sec",       0.0);
}

using ControlEvaluationTask = std::variant<
    std::monostate,               // UNSPECIFIED (0)
    TrajectoryTrackingTask,       // 1
    VelocityStepTask,             // 2
    AccelerationDecelerationTask, // 3
    StopAccuracyTask              // 4
>;

struct ControllerEvaluationRequest {
    RequestHeader          header;
    std::string            test_case_id;
    uint32_t               task_purpose{0};
    ControlEvaluationTaskType selected_task{ControlEvaluationTaskType::UNSPECIFIED};
    ControlEvaluationTask  task;
    double                 timeout_sec{0.0};
    std::string            source_iteration_id;
};

inline void from_json(const nlohmann::json& j, ControllerEvaluationRequest& r)
{
    if (j.contains("header")) r.header = j["header"].get<RequestHeader>();
    r.test_case_id       = j.value("test_case_id",       std::string{});
    r.task_purpose       = j.value("task_purpose",       uint32_t{0});
    r.selected_task      = static_cast<ControlEvaluationTaskType>(j.value("selected_task", uint32_t{0}));
    r.timeout_sec        = j.value("timeout_sec",        0.0);
    r.source_iteration_id = j.value("source_iteration_id", std::string{});

    switch (r.selected_task) {
        case ControlEvaluationTaskType::TRAJECTORY_TRACKING:
            if (j.contains("trajectory_tracking"))
                r.task = j["trajectory_tracking"].get<TrajectoryTrackingTask>();
            break;
        case ControlEvaluationTaskType::VELOCITY_STEP:
            if (j.contains("velocity_step"))
                r.task = j["velocity_step"].get<VelocityStepTask>();
            break;
        case ControlEvaluationTaskType::ACCELERATION_DECELERATION:
            if (j.contains("acceleration_deceleration"))
                r.task = j["acceleration_deceleration"].get<AccelerationDecelerationTask>();
            break;
        case ControlEvaluationTaskType::STOP_ACCURACY:
            if (j.contains("stop_accuracy"))
                r.task = j["stop_accuracy"].get<StopAccuracyTask>();
            break;
        default:
            r.task = std::monostate{};
            break;
    }
}

// ===========================================================================
// 运控响应类型
// ===========================================================================

struct ControlReadinessResponse {
    bool        success{false};
    ErrorCode   error_code{ErrorCode::OK};
    std::string message;
    bool        agent_ready{false};
    bool        trajectory_executor_ready{false};
    bool        vehicle_feedback_ready{false};
    bool        control_output_ready{false};
    bool        estop_released{false};
    bool        vehicle_safe_to_move{false};
    int64_t     checked_timestamp_us{0};
    bool        external_pose_feedback_ready{false};
    std::string external_pose_source_name;
    double      external_pose_age_ms{0.0};
    double      external_pose_quality_score{0.0};
    std::string external_pose_transport;
};

inline void to_json(nlohmann::json& j, const ControlReadinessResponse& r)
{
    j = {
        {"success",                    r.success},
        {"error_code",                 {"code", static_cast<uint32_t>(r.error_code)}},
        {"message",                    r.message},
        {"agent_ready",                r.agent_ready},
        {"trajectory_executor_ready",  r.trajectory_executor_ready},
        {"vehicle_feedback_ready",     r.vehicle_feedback_ready},
        {"control_output_ready",       r.control_output_ready},
        {"estop_released",             r.estop_released},
        {"vehicle_safe_to_move",       r.vehicle_safe_to_move},
        {"checked_timestamp_us",       r.checked_timestamp_us},
        {"external_pose_feedback_ready", r.external_pose_feedback_ready},
        {"external_pose_source_name",  r.external_pose_source_name},
        {"external_pose_age_ms",       r.external_pose_age_ms},
        {"external_pose_quality_score", r.external_pose_quality_score},
        {"external_pose_transport",    r.external_pose_transport},
    };
}

struct ControlValidationSummary {
    double rms_lateral_error_m{0.0};
    double rms_heading_error_rad{0.0};
    double rms_speed_error_ms{0.0};
    double overshoot_ratio{0.0};
    double settle_time_sec{0.0};
    double stop_position_error_m{0.0};
    double max_jerk{0.0};
    double saturation_ratio{0.0};
    bool   auto_acceptance_passed{false};
};

inline void to_json(nlohmann::json& j, const ControlValidationSummary& s)
{
    j = {
        {"rms_lateral_error_m",   s.rms_lateral_error_m},
        {"rms_heading_error_rad", s.rms_heading_error_rad},
        {"rms_speed_error_ms",    s.rms_speed_error_ms},
        {"overshoot_ratio",       s.overshoot_ratio},
        {"settle_time_sec",       s.settle_time_sec},
        {"stop_position_error_m", s.stop_position_error_m},
        {"max_jerk",              s.max_jerk},
        {"saturation_ratio",      s.saturation_ratio},
        {"auto_acceptance_passed", s.auto_acceptance_passed},
    };
}

struct ControlJobResult {
    bool                      success{false};
    ErrorCode                 error_code{ErrorCode::OK};
    std::string               message;
    std::string               job_id;
    bool                      data_quality_passed{false};
    bool                      suitable_for_commit{false};
    std::string               recommended_parameter_version;
    ControlValidationSummary  validation_summary;
    std::vector<FileReference> artifacts;
};

inline void to_json(nlohmann::json& j, const ControlJobResult& r)
{
    j = {
        {"success",                       r.success},
        {"error_code",                    {"code", static_cast<uint32_t>(r.error_code)}},
        {"message",                       r.message},
        {"job_id",                        r.job_id},
        {"data_quality_passed",           r.data_quality_passed},
        {"suitable_for_commit",           r.suitable_for_commit},
        {"recommended_parameter_version", r.recommended_parameter_version},
        {"validation_summary",            r.validation_summary},
        {"artifacts",                     r.artifacts},
    };
}

}  // namespace vaw
