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

pub mod array;
pub mod combinators;
pub mod conditionals;
pub mod core;
pub mod format;
pub mod numeric;
pub mod object;
pub mod polymorphism;
pub mod string;
pub mod util;

impl<'a> ValidationContext<'a> {
  pub(crate) fn validate_scoped(&self) -> Result<ValidationResult, ValidationError> {
    let mut result = ValidationResult::new();

    // Structural Limits
    if !self.validate_depth(&mut result)? {
      return Ok(result);
    }
    if !self.validate_always_fail(&mut result)? {
      return Ok(result);
    }
    if !self.validate_family(&mut result)? {
      return Ok(result);
    }
    if !self.validate_refs(&mut result)? {
      return Ok(result);
    }

    // Core Type Constraints
    self.validate_core(&mut result)?;
    self.validate_numeric(&mut result)?;
    self.validate_string(&mut result)?;
    self.validate_format(&mut result)?;

    // Complex Structures
    self.validate_object(&mut result)?;
    self.validate_array(&mut result)?;

    // Multipliers & Conditionals
    self.validate_combinators(&mut result)?;
    self.validate_conditionals(&mut result)?;

    // State Tracking
    self.validate_extensible(&mut result)?;
    self.validate_strictness(&mut result)?;

    Ok(result)
  }

  fn validate_depth(&self, _result: &mut ValidationResult) -> Result<bool, ValidationError> {
    if self.depth > 100 {
      Err(ValidationError {
        code: "RECURSION_LIMIT_EXCEEDED".to_string(),
        message: "Recursion limit exceeded".to_string(),
        path: self.path.to_string(),
      })
    } else {
      Ok(true)
    }
  }

  fn validate_always_fail(&self, result: &mut ValidationResult) -> Result<bool, ValidationError> {
    if self.schema.always_fail {
      result.errors.push(ValidationError {
        code: "FALSE_SCHEMA".to_string(),
        message: "Schema is false".to_string(),
        path: self.path.to_string(),
      });
      // Short-circuit
      Ok(false)
    } else {
      Ok(true)
    }
  }

  fn validate_extensible(&self, result: &mut ValidationResult) -> Result<bool, ValidationError> {
    if self.extensible {
      if let Some(obj) = self.instance.as_object() {
        result.evaluated_keys.extend(obj.keys().cloned());
      } else if let Some(arr) = self.instance.as_array() {
        result.evaluated_indices.extend(0..arr.len());
      }
    }
    Ok(true)
  }
}
