///|
pub(all) enum BookPayloadClass {
  RawEvidence
  GeneratedRecord
  AppProjection
  ImportProjection
  CommitManifest
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) enum BookCommitStatus {
  CommitReady
  CommitBlocked
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) enum BookArtifactCommitStatus {
  ArtifactReady
  ArtifactBlocked
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct BookArtifactCommit {
  artifact : BookArtifactRef
  payload_class : BookPayloadClass
  redacted : Bool
  status : BookArtifactCommitStatus
  idempotency_key : String
  message : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct BookCommitReport {
  run_id : String
  status : BookCommitStatus
  artifact_count : Int
  ready_count : Int
  blocked_count : Int
  commits : Array[BookArtifactCommit]
  summary : String
} derive(Debug, Eq, ToJson, FromJson)

///|
fn payload_class(kind : BookArtifactKind) -> BookPayloadClass {
  match kind {
    RawMarketData
    | RawPromptPacket
    | RawModelRequest
    | RawModelResponse
    | RawRunEvents => RawEvidence
    GeneratedProjection
    | GeneratedStructureLevels
    | GeneratedContextBudget
    | GeneratedDecisionPolicy
    | GeneratedAnalysisRecord
    | GeneratedExperienceSelection => GeneratedRecord
    GeneratedChartFrame => AppProjection
    ImportedLegacyRecord
    | ImportedExperienceMemory
    | ImportedTradeLog
    | GeneratedImportManifest => ImportProjection
    GeneratedBookCommit => CommitManifest
  }
}

///|
fn artifact_redacted(kind : BookArtifactKind) -> Bool {
  kind is RawPromptPacket || kind is RawModelRequest || kind is RawModelResponse
}

///|
fn artifact_blocked(artifact : BookArtifactRef) -> Bool {
  artifact.run_id == "" ||
  artifact.path == "" ||
  artifact.schema_id == "" ||
  artifact.purpose == ""
}

///|
fn idempotency_key(artifact : BookArtifactRef) -> String {
  "\{artifact.run_id}|\{artifact.schema_id}|\{artifact.path}"
}

///|
fn artifact_commit(artifact : BookArtifactRef) -> BookArtifactCommit {
  let blocked = artifact_blocked(artifact)
  {
    artifact,
    payload_class: payload_class(artifact.kind),
    redacted: artifact_redacted(artifact.kind),
    status: if blocked {
      ArtifactBlocked
    } else {
      ArtifactReady
    },
    idempotency_key: idempotency_key(artifact),
    message: if blocked {
      "artifact is missing run id, path, schema id, or purpose"
    } else {
      "artifact is ready for idempotent MoonBook commit"
    },
  }
}

///|
fn count_status(
  commits : Array[BookArtifactCommit],
  status : BookArtifactCommitStatus,
) -> Int {
  commits.fold(init=0, fn(count, commit) {
    if commit.status == status {
      count + 1
    } else {
      count
    }
  })
}

///|
fn commit_summary(report : BookCommitReport) -> String {
  if report.blocked_count == 0 {
    "book commit ready for \{report.ready_count}/\{report.artifact_count} artifact(s)"
  } else {
    "book commit blocked for \{report.blocked_count}/\{report.artifact_count} artifact(s)"
  }
}

///|
pub fn prepare_book_commit_report(plan : BookWritePlan) -> BookCommitReport {
  let commits = plan.artifacts.map(artifact_commit)
  let blocked_count = count_status(commits, ArtifactBlocked)
  let ready_count = count_status(commits, ArtifactReady)
  let report : BookCommitReport = {
    run_id: plan.run_id,
    status: if blocked_count == 0 {
      CommitReady
    } else {
      CommitBlocked
    },
    artifact_count: commits.length(),
    ready_count,
    blocked_count,
    commits,
    summary: "",
  }
  { ..report, summary: commit_summary(report) }
}