///|
pub(all) enum HarErrorCode {
  InvalidJson
  ExpectedObject
  ExpectedArray
  ExpectedString
  ExpectedNumber
  ExpectedBoolean
  MissingField
  InvalidField
  InvalidVersion
  InvalidUrl
  InvalidMethod
  InvalidStatus
  InvalidTiming
  InvalidSize
  InvalidDateTime
  InvalidEncoding
  LimitExceeded
  DuplicateIdentifier
  MissingPageReference
  ValidationFailure
} derive(Eq, Debug)

///|
pub struct HarError {
  code_value : String
  path_value : String
  message_value : String
} derive(Eq, Debug)

///|
pub fn HarErrorCode::code(self : HarErrorCode) -> String {
  match self {
    InvalidJson => "json.invalid"
    ExpectedObject => "json.expected_object"
    ExpectedArray => "json.expected_array"
    ExpectedString => "json.expected_string"
    ExpectedNumber => "json.expected_number"
    ExpectedBoolean => "json.expected_boolean"
    MissingField => "json.missing_field"
    InvalidField => "har.invalid_field"
    InvalidVersion => "har.invalid_version"
    InvalidUrl => "request.invalid_url"
    InvalidMethod => "request.invalid_method"
    InvalidStatus => "response.invalid_status"
    InvalidTiming => "timings.invalid_value"
    InvalidSize => "message.invalid_size"
    InvalidDateTime => "entry.invalid_datetime"
    InvalidEncoding => "content.invalid_encoding"
    LimitExceeded => "limits.exceeded"
    DuplicateIdentifier => "document.duplicate_identifier"
    MissingPageReference => "document.missing_page_reference"
    ValidationFailure => "validation.failure"
  }
}

///|
pub fn HarError::new(
  code : HarErrorCode,
  path : String,
  message : String,
) -> HarError {
  { code_value: code.code(), path_value: path, message_value: message }
}

///|
pub fn HarError::code(self : HarError) -> String {
  self.code_value
}

///|
pub fn HarError::path(self : HarError) -> String {
  self.path_value
}

///|
pub fn HarError::message(self : HarError) -> String {
  self.message_value
}

///|
pub fn HarError::format(self : HarError) -> String {
  self.code_value + " at " + self.path_value + ": " + self.message_value
}

///|
pub fn HarError::at_field(self : HarError, field : String) -> HarError {
  HarError::new_raw(
    self.code_value,
    append_json_field(self.path_value, field),
    self.message_value,
  )
}

///|
fn HarError::new_raw(
  code : String,
  path : String,
  message : String,
) -> HarError {
  { code_value: code, path_value: path, message_value: message }
}

///|
pub fn append_json_field(path : String, field : String) -> String {
  if path == "$" {
    "$." + field
  } else {
    path + "." + field
  }
}

///|
pub fn append_json_index(path : String, index : Int) -> String {
  path + "[" + index.to_string() + "]"
}

///|
pub struct ValidationIssue {
  severity_value : String
  code_value : String
  path_value : String
  message_value : String
} derive(Eq, Debug)

///|
pub fn ValidationIssue::error(
  code : String,
  path : String,
  message : String,
) -> ValidationIssue {
  {
    severity_value: "error",
    code_value: code,
    path_value: path,
    message_value: message,
  }
}

///|
pub fn ValidationIssue::warning(
  code : String,
  path : String,
  message : String,
) -> ValidationIssue {
  {
    severity_value: "warning",
    code_value: code,
    path_value: path,
    message_value: message,
  }
}

///|
pub fn ValidationIssue::severity(self : ValidationIssue) -> String {
  self.severity_value
}

///|
pub fn ValidationIssue::code(self : ValidationIssue) -> String {
  self.code_value
}

///|
pub fn ValidationIssue::path(self : ValidationIssue) -> String {
  self.path_value
}

///|
pub fn ValidationIssue::message(self : ValidationIssue) -> String {
  self.message_value
}

///|
pub fn ValidationIssue::format(self : ValidationIssue) -> String {
  self.severity_value +
  " " +
  self.code_value +
  " at " +
  self.path_value +
  ": " +
  self.message_value
}

///|
pub struct ValidationResult {
  issues_value : Array[ValidationIssue]
} derive(Eq, Debug)

///|
pub fn ValidationResult::new(
  issues : Array[ValidationIssue],
) -> ValidationResult {
  { issues_value: issues }
}

///|
pub fn ValidationResult::issues(
  self : ValidationResult,
) -> Array[ValidationIssue] {
  self.issues_value.copy()
}

///|
pub fn ValidationResult::issue_count(self : ValidationResult) -> Int {
  self.issues_value.length()
}

///|
pub fn ValidationResult::error_count(self : ValidationResult) -> Int {
  let mut count = 0
  for issue in self.issues_value {
    if issue.severity_value == "error" {
      count += 1
    }
  }
  count
}

///|
pub fn ValidationResult::warning_count(self : ValidationResult) -> Int {
  let mut count = 0
  for issue in self.issues_value {
    if issue.severity_value == "warning" {
      count += 1
    }
  }
  count
}

///|
pub fn ValidationResult::is_valid(self : ValidationResult) -> Bool {
  self.error_count() == 0
}