///|
fn feature_id_seen(id : String, seen : Array[String]) -> Bool {
  let mut result = false
  for item in seen {
    if item == id {
      result = true
    }
  }
  result
}

///|
/// Validate a feature without modifying it.
pub fn validate_feature(feature : Feature, index : Int) -> Array[Diagnostic] {
  let diagnostics = []
  if feature.id.trim().length() == 0 {
    diagnostics.push(
      error_diagnostic(
        code="feature.id.empty",
        message="feature id must not be blank",
        index~,
      ),
    )
  }
  if feature.lower > feature.upper {
    diagnostics.push(
      error_diagnostic(
        code="feature.tolerance.reversed",
        message="lower tolerance must not exceed upper tolerance",
        index~,
      ),
    )
  }
  diagnostics
}

///|
/// Validate a device without modifying it.
pub fn validate_device(device : Device, index : Int) -> Array[Diagnostic] {
  let diagnostics = []
  if device.id.trim().length() == 0 {
    diagnostics.push(
      error_diagnostic(
        code="device.id.empty",
        message="device id must not be blank",
        index~,
      ),
    )
  }
  if device.accuracy <= 0.0 {
    diagnostics.push(
      error_diagnostic(
        code="device.accuracy.non_positive",
        message="device accuracy must be positive",
        index~,
      ),
    )
  }
  if device.reach <= 0.0 {
    diagnostics.push(
      error_diagnostic(
        code="device.reach.non_positive",
        message="device reach must be positive",
        index~,
      ),
    )
  }
  if device.supported_kinds.length() == 0 {
    diagnostics.push(
      warning_diagnostic(
        code="device.kinds.empty",
        message="device has no supported feature kinds",
        index~,
      ),
    )
  }
  diagnostics
}

///|
/// Validate all features and devices, including duplicate feature identifiers.
pub fn validate_catalog(
  features : Array[Feature],
  devices : Array[Device],
) -> Array[Diagnostic] {
  let diagnostics = []
  let seen_features = []
  for i, feature in features {
    for diagnostic in validate_feature(feature, i) {
      diagnostics.push(diagnostic)
    }
    if feature_id_seen(feature.id, seen_features) {
      diagnostics.push(
        error_diagnostic(
          code="feature.id.duplicate",
          message="feature id is duplicated: " + feature.id,
          index=i,
        ),
      )
    } else {
      seen_features.push(feature.id)
    }
  }
  for i, device in devices {
    for diagnostic in validate_device(device, i) {
      diagnostics.push(diagnostic)
    }
  }
  diagnostics
}