///|
/// Immutable, complete block records authenticated by an independent byte pin.
/// Uses the existing MFL1 schema, but is not a local progress checkpoint. Loading
/// a reference never confirms local storage; every fresh session starts recovery.
pub struct BlockReference {
  spec : ObjectSpec
  chunk_size : Int32
  priv checkpoint : String
}

///|
/// Publish block records only after the entire indexed source digest verifies.
/// Repeated calls produce identical MFL1 bytes and independent recovery sessions.
pub fn StorageIndexer::block_reference(
  self : StorageIndexer,
) -> BlockReference raise LedgerError {
  let complete = self.finish()
  {
    spec: complete.spec,
    chunk_size: complete.chunk_size,
    checkpoint: complete.checkpoint(),
  }
}

///|
/// Authenticate exact bytes BEFORE UTF-8/schema decoding. The pin must come from
/// a separate trusted channel. Require the expected identity and every block,
/// including the short final block. Partial checkpoints are not references.
pub fn BlockReference::from_bytes(
  bytes : Bytes,
  expected_sha256 : String,
  expected : ObjectSpec,
) -> BlockReference raise LedgerError {
  if !valid_digest(expected_sha256) {
    raise InvalidCheckpoint(
      "block reference pin must be 64 lowercase SHA-256 hex digits",
    )
  }
  if bytes.length() > 16000000 {
    raise InvalidCheckpoint("block reference exceeds 16000000 bytes")
  }
  if digest(bytes) != expected_sha256 {
    raise InvalidCheckpoint(
      "block reference differs from trusted byte pin; retain input",
    )
  }
  let checkpoint = @utf8.decode(bytes) catch {
    _ =>
      raise InvalidCheckpoint(
        "block reference requires strict UTF-8; retain input",
      )
  }
  let session = restore(checkpoint, expected)
  for block in session.blocks {
    if !(block is Unverified(_)) {
      raise InvalidCheckpoint(
        "block reference requires every block record; partial progress is not a reference",
      )
    }
  }
  { spec: expected, chunk_size: session.chunk_size, checkpoint, }
}

///|
/// Producers emit canonical MFL1; consumers retain the exact authenticated text,
/// including whitespace. Do not recompute a supplied byte pin from re-encoded JSON.
pub fn BlockReference::to_checkpoint(self : BlockReference) -> String {
  self.checkpoint
}

///|
/// Return a fresh session with all records untrusted until actual block readback.
/// Caller must reconcile storage and finish recovery before reserving repairs.
pub fn BlockReference::session(
  self : BlockReference,
) -> Session raise LedgerError {
  restore(self.checkpoint, self.spec)
}