///|
/// Unix timestamp in whole seconds. Callers provide timestamps explicitly so
/// all cache decisions remain deterministic.
pub type Timestamp = Int64

///|
/// Whether a decision is made for a single-user or shared HTTP cache.
pub(all) enum CacheMode {
  PrivateCache
  SharedCache
} derive(Debug, Eq)

///|
/// Request metadata required by RFC 9111 decisions.
pub(all) struct RequestMetadata {
  http_method : String
  target_uri : String
  headers : Headers
} derive(Debug, Eq)

///|
/// Response metadata required by RFC 9111 decisions. Bodies deliberately stay
/// outside this library.
pub(all) struct ResponseMetadata {
  status : Int
  headers : Headers
} derive(Debug, Eq)

///|
/// Metadata retained by the caller for a stored response.
pub(all) struct StoredResponse {
  request : RequestMetadata
  response : ResponseMetadata
  request_time : Timestamp
  response_time : Timestamp
} derive(Debug, Eq)

///|
/// Caller-controlled choices for behavior that RFC 9111 leaves discretionary.
pub(all) struct CachePolicy {
  allow_heuristic_freshness : Bool
  heuristic_fraction_percent : Int
  heuristic_max_seconds : Int64
  allow_disconnected_stale : Bool
} derive(Debug, Eq)

///|
/// Conservative defaults suitable for a standards-focused implementation.
pub fn default_policy() -> CachePolicy {
  {
    allow_heuristic_freshness: true,
    heuristic_fraction_percent: 10,
    heuristic_max_seconds: 86400L,
    allow_disconnected_stale: false,
  }
}

///|
/// Machine-stable diagnostic severity.
pub(all) enum DiagnosticLevel {
  Info
  Warning
  Error
} derive(Debug, Eq)

///|
/// A non-fatal parser or evaluation observation.
pub(all) struct Diagnostic {
  level : DiagnosticLevel
  code : String
  message : String
  field_name : String?
} derive(Debug, Eq)

///|
/// One machine-stable explanation step.
pub(all) struct TraceStep {
  code : String
  message : String
  rfc_section : String
} derive(Debug, Eq)

///|
/// Construct validated request metadata.
pub fn request(
  http_method : String,
  target_uri : String,
  headers? : Headers = Headers::empty(),
) -> RequestMetadata {
  { http_method: http_method.to_upper(), target_uri, headers, }
}

///|
/// Construct response metadata without a body.
pub fn response(
  status : Int,
  headers? : Headers = Headers::empty(),
) -> ResponseMetadata {
  { status, headers, }
}

///|
/// Construct stored response metadata with explicit request/response times.
pub fn stored_response(
  request : RequestMetadata,
  response : ResponseMetadata,
  request_time : Timestamp,
  response_time : Timestamp,
) -> StoredResponse {
  { request, response, request_time, response_time, }
}