# | Reusable Validation Library for Nickel
# | Common validation contracts and helper functions
# | Author: JesusPerezLorenzo
# | Date: 2025-12-15
# | Status: Production Ready

# ============================================================
# Common Validation Contracts
# ============================================================

# IPv4 address validation (e.g., "192.168.1.1")
let IpV4Contract = {
  label = "ValidIPv4",
  predicate = fun ip =>
    std.string.is_match ip "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
}

# CIDR notation validation (e.g., "192.168.1.0/24")
let CidrContract = {
  label = "ValidCIDR",
  predicate = fun cidr =>
    std.string.is_match cidr "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/\\d{1,2}$"
}

# Port range validation (1-65535)
let PortContract = {
  label = "ValidPort",
  predicate = fun p =>
    p > 0 && p < 65536
}

# Semantic versioning validation (e.g., "1.2.3")
let SemverContract = {
  label = "ValidSemver",
  predicate = fun v =>
    std.string.is_match v "^\\d+\\.\\d+\\.\\d+$"
}

# Domain name validation (e.g., "example.com")
let DomainContract = {
  label = "ValidDomain",
  predicate = fun d =>
    std.string.is_match d "^[a-z0-9]([a-z0-9-\\.]{0,253}[a-z0-9])?$"
}

# OCI tag validation (e.g., "latest", "v1.0.0", "sha256-abc123")
let OciTagContract = {
  label = "ValidOCITag",
  predicate = fun tag =>
    std.string.is_match tag "^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$"
}

# ISO 8601 timestamp validation (e.g., "2025-12-15T10:30:00Z")
let Iso8601Contract = {
  label = "ValidISO8601",
  predicate = fun ts =>
    std.string.is_match ts "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$"
}

# Filesystem path validation (simple: non-empty, no double slashes)
let PathContract = {
  label = "ValidPath",
  predicate = fun path =>
    std.string.length path > 0 && !std.string.contains path "//"
}

# ============================================================
# Helper Functions for Common Validations
# ============================================================

# Validate minimum string length
let min_length = fun min_val =>
  {
    label = "MinLength%{std.to_string min_val}",
    predicate = fun s =>
      std.string.length s >= min_val
  }

# Validate maximum string length
let max_length = fun max_val =>
  {
    label = "MaxLength%{std.to_string max_val}",
    predicate = fun s =>
      std.string.length s <= max_val
  }

# Validate numeric range
let range = fun min_val max_val =>
  {
    label = "Range[%{std.to_string min_val}-%{std.to_string max_val}]",
    predicate = fun n =>
      n >= min_val && n <= max_val
  }

# Validate enum (value must be in list)
let enum = fun values =>
  {
    label = "Enum[%{std.string.join "," values}]",
    predicate = fun v =>
      std.array.elem v values
  }

# Validate non-empty string
let non_empty_string = {
  label = "NonEmptyString",
  predicate = fun s =>
    std.string.length s > 0
}

# Validate non-negative number
let non_negative = {
  label = "NonNegative",
  predicate = fun n =>
    n >= 0
}

# Validate positive number
let positive = {
  label = "Positive",
  predicate = fun n =>
    n > 0
}

# Validate boolean value
let boolean_value = {
  label = "Boolean",
  predicate = fun b =>
    b == true || b == false
}

# ============================================================
# Helper Functions for Custom Validation
# ============================================================

# Validate all items in array satisfy predicate
let all_items = fun predicate =>
  fun items =>
    std.array.all predicate items

# Validate at least one item in array satisfies predicate
let any_items = fun predicate =>
  fun items =>
    std.array.any predicate items

# Validate record has all required keys
let has_keys = fun required_keys =>
  fun record =>
    std.array.all
      (fun key =>
        std.record.has_field record key
      )
      required_keys

# ============================================================
# Exports
# ============================================================

{
  # Core validation contracts
  IpV4Contract = IpV4Contract,
  CidrContract = CidrContract,
  PortContract = PortContract,
  SemverContract = SemverContract,
  DomainContract = DomainContract,
  OciTagContract = OciTagContract,
  Iso8601Contract = Iso8601Contract,
  PathContract = PathContract,

  # Helper functions
  min_length = min_length,
  max_length = max_length,
  range = range,
  enum = enum,
  non_empty_string = non_empty_string,
  non_negative = non_negative,
  positive = positive,
  boolean_value = boolean_value,

  # Custom validators
  all_items = all_items,
  any_items = any_items,
  has_keys = has_keys,
}
