agent-device-rec 0.1.0

Health device recommendation engine for longevity monitoring
use serde::{Deserialize, Serialize};

// ─── labassess input contract (what we consume) ───
// These structs must match the labassess JSON contract. Some fields are only
// used for deserialization fidelity, not directly read by recommend.rs.

#[allow(dead_code)]
#[derive(Debug, Clone, Deserialize)]
pub struct LabassessOutput {
    pub version: String,
    pub status: String,
    pub data: LabassessData,
}

#[allow(dead_code)]
#[derive(Debug, Clone, Deserialize)]
pub struct LabassessData {
    pub mode: String,
    pub patient: PatientInfo,
    pub scored_biomarkers: Vec<ScoredBiomarker>,
    #[serde(default)]
    pub derived_values: Vec<DerivedValue>,
    #[serde(default)]
    pub patterns_detected: Vec<PatternDetected>,
    #[serde(default)]
    pub red_flags: Vec<RedFlag>,
    pub summary: Summary,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct PatientInfo {
    pub sex: Option<String>,
    pub age: Option<u8>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct ScoredBiomarker {
    pub name: String,
    pub standardized_name: String,
    pub value: f64,
    pub unit: String,
    pub status: String,
    pub severity: String,
}

#[allow(dead_code)]
#[derive(Debug, Clone, Deserialize)]
pub struct DerivedValue {
    pub name: String,
    pub value: f64,
    pub status: String,
}

#[allow(dead_code)]
#[derive(Debug, Clone, Deserialize)]
pub struct PatternDetected {
    pub name: String,
    pub confidence: String,
    #[serde(default)]
    pub criteria_met: Vec<String>,
    #[serde(default)]
    pub action: String,
}

#[allow(dead_code)]
#[derive(Debug, Clone, Deserialize)]
pub struct RedFlag {
    pub marker: String,
    pub value: f64,
    pub unit: String,
    pub urgency: String,
    #[serde(default)]
    pub action: String,
    #[serde(default)]
    pub referral: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Summary {
    pub total_markers: usize,
    pub scored: usize,
    pub unknown: usize,
    pub optimal: usize,
    pub good: usize,
    pub attention: usize,
    pub marginal: usize,
    pub concern: usize,
}

// ─── Device catalog types (TOML) ───

#[derive(Debug, Clone, Deserialize)]
pub struct DeviceCatalogFile {
    #[serde(default)]
    pub device: Vec<Device>,
    #[serde(default)]
    pub brand: Vec<DeviceBrand>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Device {
    pub id: String,
    pub name: String,
    pub brand_id: String,
    pub category: String,
    pub description: String,
    pub price_range: String,
    pub price_usd: Option<u32>,
    pub connectivity: Vec<String>,
    pub platforms: Vec<String>,
    #[serde(default)]
    pub tracks: Vec<TrackableMetric>,
    #[serde(default)]
    pub use_cases: Vec<String>,
    #[serde(default)]
    pub integrations: Vec<String>,
    #[serde(default)]
    pub notes: String,
    #[serde(default)]
    pub prescription_required: bool,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TrackableMetric {
    pub metric: String,
    pub accuracy: String,
    #[serde(default)]
    pub notes: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DeviceBrand {
    pub id: String,
    pub name: String,
    pub website: String,
    pub country: String,
    pub verified: bool,
}

// ─── Output types ───

#[derive(Debug, Clone, Serialize)]
pub struct DeviceRecommendation {
    pub priority: String,
    pub device: Device,
    pub rationale: String,
    pub relevant_patterns: Vec<String>,
    pub relevant_biomarkers: Vec<String>,
    pub score: f64,
}

#[derive(Debug, Clone, Serialize)]
pub struct DeviceRecommendOutput {
    pub patient: PatientInfo,
    pub recommendations: Vec<DeviceRecommendation>,
    pub total_recommendations: usize,
}

#[derive(Debug, Clone, Serialize)]
pub struct DeviceComparison {
    pub devices: Vec<Device>,
    pub comparison_matrix: Vec<ComparisonRow>,
}

#[derive(Debug, Clone, Serialize)]
pub struct ComparisonRow {
    pub attribute: String,
    pub values: Vec<String>,
}