use crate::database::Database;
use crate::database::schema::Schema;
use crate::validator::error::ValidationError;
use crate::validator::result::ValidationResult;
use std::collections::HashSet;
use std::sync::Arc;

pub struct ValidationContext<'a> {
  pub db: &'a Arc<Database>,
  pub root: &'a Schema,
  pub schema: &'a Schema,
  pub instance: &'a serde_json::Value,
  pub path: String,
  pub depth: usize,
  pub extensible: bool,
  pub reporter: bool,
  pub overrides: HashSet<String>,
}

impl<'a> ValidationContext<'a> {
  pub fn new(
    db: &'a Arc<Database>,
    root: &'a Schema,
    schema: &'a Schema,
    instance: &'a serde_json::Value,
    overrides: HashSet<String>,
    extensible: bool,
    reporter: bool,
  ) -> Self {
    let effective_extensible = schema.extensible.unwrap_or(extensible);
    Self {
      db,
      root,
      schema,
      instance,
      path: String::new(),
      depth: 0,
      extensible: effective_extensible,
      reporter,
      overrides,
    }
  }

  pub fn derive(
    &self,
    schema: &'a Schema,
    instance: &'a serde_json::Value,
    path: &str,
    overrides: HashSet<String>,
    extensible: bool,
    reporter: bool,
  ) -> Self {
    let effective_extensible = schema.extensible.unwrap_or(extensible);

    Self {
      db: self.db,
      root: self.root,
      schema,
      instance,
      path: path.to_string(),
      depth: self.depth + 1,
      extensible: effective_extensible,
      reporter,
      overrides,
    }
  }

  pub fn derive_for_schema(&self, schema: &'a Schema, reporter: bool) -> Self {
    self.derive(
      schema,
      self.instance,
      &self.path,
      HashSet::new(),
      self.extensible,
      reporter,
    )
  }

  pub fn validate(&self) -> Result<ValidationResult, ValidationError> {
    self.validate_scoped()
  }
}
