// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

// `format`, and the assertion the specification asks for.
//
// A format is a name and a question about a string. There is one table of them
// and one call, because a format is a format: the keyword is the same in every
// version, and only whether it asserts changes.

///|
/// Whether `text` is the format `name` names.
///
/// `None` when the name is one this library does not know, which is not the
/// same as a name it knows and the text failing: a caller has to be able to tell
/// "not this format" from "not a format at all".
fn judge_format(name : String, text : String, draft : Draft) -> Bool? {
  match name {
    "date" => Some(is_date(text))
    "time" => Some(is_time(text, if draft == V1 { Refused } else { Allowed }))
    "date-time" => Some(is_date_time(text))
    "duration" => Some(is_duration(text))
    "email" => Some(is_email(text, Ascii))
    "idn-email" => Some(is_email(text, International))
    "hostname" => Some(is_hostname(text))
    "idn-hostname" => Some(is_idn_hostname(text))
    "ipv4" => Some(is_ipv4(text))
    "ipv6" => Some(is_ipv6(text))
    "uri" => Some(is_uri(text, Ascii))
    "uri-reference" => Some(is_uri_reference(text, Ascii))
    "iri" => Some(is_uri(text, International))
    "iri-reference" => Some(is_uri_reference(text, International))
    "uri-template" => Some(is_uri_template(text))
    "uuid" => Some(is_uuid(text))
    "json-pointer" => Some(is_json_pointer(text))
    "relative-json-pointer" => Some(is_relative_json_pointer(text))
    "regex" => Some(is_regex(text))
    _ => None
  }
}

///|
/// Whether `format` names a format this library knows.
///
/// v1 requires a schema naming one it does not know to be refused rather than
/// read with the keyword ignored, which is what this answers for.
fn known_format(name : String) -> Bool {
  judge_format(name, "", Draft2020) is Some(_)
}

///|
/// `format` as an assertion, which it is only when the caller or the document's
/// dialect asked for one.
fn Schema::check_format(
  self : Schema,
  schema : Json,
  value : Json,
  at : String,
  spath : String,
  sink : Array[OutputUnit]?,
) -> Bool {
  guard self.asserts_format else { return true }
  guard schema is String(name) && value is String(text) else { return true }
  // A name nobody here knows asserts nothing: an unknown format is not a
  // failure of the instance, and only v1 makes it a failure of the schema.
  match judge_format(name, text, self.draft) {
    Some(true) => true
    Some(false) => note(sink, at, spath, "format", "not a valid " + name)
    None => true
  }
}