use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError;
use crate::validator::result::ValidationResult;

impl<'a> ValidationContext<'a> {
  pub(crate) fn validate_numeric(
    &self,
    result: &mut ValidationResult,
  ) -> Result<bool, ValidationError> {
    let current = self.instance;
    if let Some(num) = current.as_f64() {
      if let Some(min) = self.schema.minimum
        && num < min
      {
        result.errors.push(ValidationError {
          code: "MINIMUM_VIOLATED".to_string(),
          message: format!("Value {} < min {}", num, min),
          path: self.path.to_string(),
        });
      }
      if let Some(max) = self.schema.maximum
        && num > max
      {
        result.errors.push(ValidationError {
          code: "MAXIMUM_VIOLATED".to_string(),
          message: format!("Value {} > max {}", num, max),
          path: self.path.to_string(),
        });
      }
      if let Some(ex_min) = self.schema.exclusive_minimum
        && num <= ex_min
      {
        result.errors.push(ValidationError {
          code: "EXCLUSIVE_MINIMUM_VIOLATED".to_string(),
          message: format!("Value {} <= ex_min {}", num, ex_min),
          path: self.path.to_string(),
        });
      }
      if let Some(ex_max) = self.schema.exclusive_maximum
        && num >= ex_max
      {
        result.errors.push(ValidationError {
          code: "EXCLUSIVE_MAXIMUM_VIOLATED".to_string(),
          message: format!("Value {} >= ex_max {}", num, ex_max),
          path: self.path.to_string(),
        });
      }
      if let Some(multiple_of) = self.schema.multiple_of {
        let val: f64 = num / multiple_of;
        if (val - val.round()).abs() > f64::EPSILON {
          result.errors.push(ValidationError {
            code: "MULTIPLE_OF_VIOLATED".to_string(),
            message: format!("Value {} not multiple of {}", num, multiple_of),
            path: self.path.to_string(),
          });
        }
      }
    }
    Ok(true)
  }
}
