///|
/// Deterministic scenario generators for regression and benchmark testing.

///|
/// Scenario type for synthetic RR data.
pub(all) enum SimulationScenario {
  Stable
  RespiratoryModulated
  GradualDrift
  ExerciseTransition
  ArtifactBurst
} derive(FromJson, ToJson, Debug, Eq)

///|
/// Simulation parameters.
pub(all) struct SimulationConfig {
  length : Int
  baseline_rr : Double
  variability_ms : Double
  sample_rate_hz : Double
  scenario : SimulationScenario
  artifact_period : Int
} derive(FromJson, ToJson, Debug, Eq)

///|
/// Default deterministic simulation configuration.
pub fn SimulationConfig::default() -> SimulationConfig {
  {
    length: 300,
    baseline_rr: 800.0,
    variability_ms: 25.0,
    sample_rate_hz: 4.0,
    scenario: Stable,
    artifact_period: 37,
  }
}

///|
fn simulation_wave(index : Int, sample_rate_hz : Double) -> Double {
  let safe_rate = if sample_rate_hz <= 0.0 { 1.0 } else { sample_rate_hz }
  let time = index.to_double() / safe_rate
  0.60 * @math.sin(2.0 * 3.141592653589793 * 0.10 * time) +
  0.30 * @math.sin(2.0 * 3.141592653589793 * 0.25 * time + 0.3) +
  0.10 * @math.sin(2.0 * 3.141592653589793 * 0.03 * time)
}

///|
/// Generate one scenario without random state.
pub fn simulate_rr(config : SimulationConfig) -> Array[Double] {
  let length = if config.length < 0 { 0 } else { config.length }
  let result = []
  for i in 0.. config.baseline_rr + config.variability_ms * wave
      RespiratoryModulated =>
        config.baseline_rr + config.variability_ms * 2.0 * wave
      GradualDrift =>
        config.baseline_rr +
        config.variability_ms * wave +
        120.0 * (drift - 0.5)
      ExerciseTransition =>
        if drift < 0.5 {
          config.baseline_rr + config.variability_ms * wave
        } else {
          config.baseline_rr - 180.0 + config.variability_ms * wave
        }
      ArtifactBurst =>
        if config.artifact_period > 0 && i % config.artifact_period == 0 {
          config.baseline_rr * 3.0
        } else {
          config.baseline_rr + config.variability_ms * wave
        }
    }
    result.push(value)
  }
  result
}

///|
/// Generate a direct sinusoidal respiratory trace.
pub fn simulate_respiratory_trace(
  length : Int,
  sample_rate_hz : Double,
  rate_bpm : Double,
) -> Array[Double] {
  let result = []
  if length <= 0 || sample_rate_hz <= 0.0 {
    return result
  }
  let frequency = rate_bpm / 60.0
  for i in 0.. Array[AmbulatorySample] {
  let intervals = simulate_rr(config)
  let result = []
  let mut timestamp = 0.0
  for i in 0.. intervals.length() / 2 {
      0.6
    } else {
      0.02
    }
    result.push({
      timestamp_seconds: timestamp,
      rr_ms: rr,
      heart_rate_bpm: hr,
      movement,
      temperature_c: 36.5 + 0.1 * simulation_wave(i, config.sample_rate_hz),
      quality_ratio: if rr > 2000.0 {
        0.3
      } else {
        0.98
      },
    })
    timestamp += rr / 1000.0
  }
  result
}

///|
/// Inject a deterministic missing-value run.
pub fn inject_missing_run(
  values : Array[Double],
  start : Int,
  length : Int,
) -> Array[Double] {
  let result = []
  for value in values {
    result.push(value)
  }
  let from = if start < 0 { 0 } else { start }
  let safe_length = if length < 0 { 0 } else { length }
  let to = if from + safe_length > result.length() {
    result.length()
  } else {
    from + safe_length
  }
  for i in from.. Array[Double] {
  if resolution_ms <= 0.0 {
    return values
  }
  let result = []
  for i in 0.. Array[String] {
  ["stable", "respiratory", "drift", "exercise_transition", "artifact_burst"]
}

///|
/// Parse a scenario name with stable fallback behavior.
pub fn parse_simulation_scenario(name : String) -> SimulationScenario {
  match name {
    "respiratory" => RespiratoryModulated
    "drift" => GradualDrift
    "exercise_transition" => ExerciseTransition
    "artifact_burst" => ArtifactBurst
    _ => Stable
  }
}

///|
/// Return a compact set of scenario validation metrics.
pub fn simulation_summary(
  values : Array[Double],
  config : HrvConfig,
) -> Array[Double] {
  let validation = validate_intervals(values, config)
  let quality = evaluate_signal_quality(
    values,
    config,
    SignalQualityWeights::default(),
    30,
    300,
  )
  [
    values.length().to_double(),
    validation.valid.to_double(),
    validation.invalid.to_double(),
    quality.score,
    mean_value(values),
    calculate_rmssd(values),
    calculate_sdnn(values),
  ]
}

///|
/// Run all scenarios with one shared length for smoke tests.
pub fn simulate_scenario_matrix(
  length : Int,
  baseline_rr : Double,
) -> Array[Array[Double]] {
  let result = []
  for
    scenario in [
      Stable,
      RespiratoryModulated,
      GradualDrift,
      ExerciseTransition,
      ArtifactBurst,
    ] {
    let config : SimulationConfig = {
      length,
      baseline_rr,
      variability_ms: 25.0,
      sample_rate_hz: 4.0,
      scenario,
      artifact_period: 37,
    }
    result.push(simulation_summary(simulate_rr(config), HrvConfig::default()))
  }
  result
}