//! FMU IO map: declares which model parameters are PLC inputs and which result
//! fields are PLC outputs. This is a sidecar JSON (`fmu_io.json`) bundled inside
//! the `.fmu` so the Entropyk `ScenarioConfig` schema stays untouched.
//!
//! ## Example `fmu_io.json`
//!
//! ```json
//! {
//!   "inputs": [
//!     { "name": "T_air_c",  "component": "cond_air_in",   "param": "t_dry_c" },
//!     { "name": "T_water_c","component": "evap_water_in",  "param": "t_set_c" },
//!     { "name": "exv_open", "component": "exv",            "param": "opening" }
//!   ],
//!   "outputs": [
//!     { "name": "COP",        "kind": "cop" },
//!     { "name": "Q_cool_kW",  "kind": "q_cooling_kw" },
//!     { "name": "P_kW",      "kind": "compressor_power_kw" },
//!     { "name": "P_evap_bar","kind": "pressure_bar",    "edge": 3 },
//!     { "name": "h_evap",     "kind": "enthalpy_kj_kg", "edge": 3 }
//!   ]
//! }
//! ```
//!
//! Value references are assigned in declaration order: inputs first
//! (`0..n_inputs`), then outputs (`n_inputs..n_inputs+n_outputs`).

use serde::Deserialize;

/// Top-level IO specification.
#[derive(Debug, Clone, Deserialize)]
pub struct FmuIoSpec {
    /// PLC inputs: written by the host into model parameters each cycle.
    #[serde(default)]
    pub inputs: Vec<IoInput>,
    /// PLC outputs: read by the host after each `doStep`.
    #[serde(default)]
    pub outputs: Vec<IoOutput>,
}

/// One PLC input, bound to a component parameter.
#[derive(Debug, Clone, Deserialize)]
pub struct IoInput {
    /// Human-readable name (mirrors `modelDescription.xml` ScalarVariable name).
    pub name: String,
    /// Target component name (must match a `"name"` in the model JSON).
    pub component: String,
    /// Target parameter key inside that component's `params` object.
    pub param: String,
}

/// One PLC output, extracted from the simulation result.
///
/// `kind` selects the result field; `edge` is required for edge-scoped outputs
/// (`pressure_bar`, `enthalpy_kj_kg`, `mass_flow_kg_s`) and ignored otherwise.
#[derive(Debug, Clone, Deserialize)]
pub struct IoOutput {
    /// Human-readable name.
    pub name: String,
    /// Result field: `cop`, `q_cooling_kw`, `q_heating_kw`, `compressor_power_kw`,
    /// `pressure_bar`, `enthalpy_kj_kg`, `mass_flow_kg_s`.
    pub kind: String,
    /// Edge index for edge-scoped outputs.
    #[serde(default)]
    pub edge: Option<usize>,
}
