///|
fn quoted_json(value : String) -> String {
  Json::string(value).stringify()
}

///|
fn append_instruction_json(
  builder : StringBuilder,
  item : TraceInstruction,
) -> Unit {
  builder <+ "{"
  builder <+ "\"window_index\":\{item.window_index},"
  builder <+ "\"ordinal\":\{item.ordinal},"
  builder <+ "\"code_index\":\{item.code_index},"
  builder <+ "\"code_offset\":\{item.code_offset},"
  builder <+ "\"code_slot\":\{item.code_slot},"
  builder <+ "\"kind\":"
  builder.write_string(quoted_json(item.kind.name()))
  builder <+ ",\"size\":\{item.size},"
  builder <+ "\"mode\":\{item.mode},"
  builder <+ "\"target_offset\":\{item.target_offset},"
  builder <+ "\"data_offset\":\{item.data_offset},"
  builder <+ "\"data_size\":\{item.data_size},"
  builder <+ "\"address_offset\":\{item.address_offset},"
  builder <+ "\"address\":\{item.address}"
  builder <+ "}"
}

///|
/// Renders the expanded instruction trace as compact valid JSON.
pub fn DeltaTrace::to_json(self : DeltaTrace) -> String {
  let builder = StringBuilder()
  builder <+ "{\"format\":\"VCDIFF\","
  builder <+ "\"file_size\":\{self.file_size},"
  builder <+ "\"window_count\":\{self.window_count},"
  builder <+ "\"target_size\":\{self.target_size},"
  builder <+ "\"instruction_count\":\{self.instruction_count},"
  builder <+ "\"add_count\":\{self.add_count},"
  builder <+ "\"run_count\":\{self.run_count},"
  builder <+ "\"copy_count\":\{self.copy_count},"
  builder <+ "\"instructions\":["
  for index, item in self.instructions {
    if index > 0 {
      builder <+ ","
    }
    append_instruction_json(builder, item)
  }
  builder <+ "]}"
  builder.to_string()
}

///|
fn append_int_array_json(builder : StringBuilder, values : Array[Int]) -> Unit {
  builder <+ "["
  for index, value in values {
    if index > 0 {
      builder <+ ","
    }
    builder <+ "\{value}"
  }
  builder <+ "]"
}

///|
fn append_operation_statistics_json(
  builder : StringBuilder,
  report : InstructionStatistics,
) -> Unit {
  builder <+ "{"
  builder <+ "\"instruction_count\":\{report.instruction_count},"
  builder <+ "\"add_count\":\{report.add_count},"
  builder <+ "\"run_count\":\{report.run_count},"
  builder <+ "\"copy_count\":\{report.copy_count},"
  builder <+ "\"add_bytes\":\{report.add_bytes},"
  builder <+ "\"run_bytes\":\{report.run_bytes},"
  builder <+ "\"copy_bytes\":\{report.copy_bytes},"
  builder <+ "\"literal_bytes\":\{report.literal_bytes},"
  builder <+ "\"copy_percentage\":\{report.copy_percentage()},"
  builder <+ "\"run_percentage\":\{report.run_percentage()},"
  builder <+ "\"maximum_instruction_size\":\{report.maximum_instruction_size},"
  builder <+ "\"size_buckets\":{"
  builder <+ "\"tiny\":\{report.tiny_instructions},"
  builder <+ "\"small\":\{report.small_instructions},"
  builder <+ "\"medium\":\{report.medium_instructions},"
  builder <+ "\"large\":\{report.large_instructions}},"
  builder <+ "\"copy_mode_counts\":"
  append_int_array_json(builder, report.copy_mode_counts)
  builder <+ "}"
}

///|
fn append_window_statistics_json(
  builder : StringBuilder,
  report : WindowStatistics,
) -> Unit {
  builder <+ "{"
  builder <+ "\"window_index\":\{report.window_index},"
  builder <+ "\"target_size\":\{report.target_size},"
  builder <+ "\"delta_size\":\{report.delta_size},"
  builder <+ "\"data_size\":\{report.data_size},"
  builder <+ "\"instruction_size\":\{report.instruction_size},"
  builder <+ "\"address_size\":\{report.address_size},"
  builder <+ "\"operations\":"
  append_operation_statistics_json(builder, report.operations)
  builder <+ "}"
}

///|
/// Renders semantic and encoded-size statistics as compact valid JSON.
pub fn DeltaStatistics::to_json(self : DeltaStatistics) -> String {
  let builder = StringBuilder()
  builder <+ "{\"format\":\"VCDIFF\","
  builder <+ "\"file_size\":\{self.file_size},"
  builder <+ "\"target_size\":\{self.target_size},"
  builder <+ "\"window_count\":\{self.window_count},"
  builder <+ "\"encoded_per_mille\":\{self.encoded_per_mille()},"
  builder <+ "\"header_bytes\":\{self.header_bytes},"
  builder <+ "\"window_header_bytes\":\{self.window_header_bytes},"
  builder <+ "\"data_bytes\":\{self.data_bytes},"
  builder <+ "\"instruction_bytes\":\{self.instruction_bytes},"
  builder <+ "\"address_bytes\":\{self.address_bytes},"
  builder <+ "\"operations\":"
  append_operation_statistics_json(builder, self.operations)
  builder <+ ",\"windows\":["
  for index, window in self.windows {
    if index > 0 {
      builder <+ ","
    }
    append_window_statistics_json(builder, window)
  }
  builder <+ "]}"
  builder.to_string()
}

///|
fn append_diagnostic_json(
  builder : StringBuilder,
  item : AuditDiagnostic,
) -> Unit {
  builder <+ "{\"level\":"
  builder.write_string(quoted_json(item.level.name()))
  builder <+ ",\"code\":"
  builder.write_string(quoted_json(item.code))
  builder <+ ",\"message\":"
  builder.write_string(quoted_json(item.message))
  builder <+ ",\"offset\":\{item.offset}}"
}

///|
/// Renders an audit result as compact valid JSON.
pub fn AuditReport::to_json(self : AuditReport) -> String {
  let builder = StringBuilder()
  builder <+ "{\"structurally_valid\":"
  append_json_bool(builder, self.structurally_valid)
  builder <+ ",\"decodable\":"
  append_json_bool(builder, self.decodable)
  builder <+ ",\"decoded_size\":\{self.decoded_size},"
  builder <+ "\"resources\":{"
  builder <+ "\"input_size\":\{self.resources.input_size},"
  builder <+ "\"declared_output_size\":\{self.resources.declared_output_size},"
  builder <+ "\"largest_window_size\":\{self.resources.largest_window_size},"
  builder <+
    "\"largest_dictionary_size\":\{self.resources.largest_dictionary_size},"
  builder <+ "\"total_instructions\":\{self.resources.total_instructions},"
  builder <+ "\"estimated_peak_bytes\":\{self.resources.estimated_peak_bytes}},"
  builder <+ "\"diagnostics\":["
  for index, item in self.diagnostics {
    if index > 0 {
      builder <+ ","
    }
    append_diagnostic_json(builder, item)
  }
  builder <+ "]}"
  builder.to_string()
}

///|
/// Renders a verification result as compact valid JSON.
pub fn VerifyReport::to_json(self : VerifyReport) -> String {
  let builder = StringBuilder()
  builder <+ "{\"matches\":"
  append_json_bool(builder, self.matches)
  builder <+ ",\"expected_size\":\{self.expected_size},"
  builder <+ "\"actual_size\":\{self.actual_size},"
  builder <+ "\"first_mismatch\":\{self.first_mismatch}}"
  builder.to_string()
}

///|
/// Renders a stable delta comparison as compact valid JSON.
pub fn DeltaComparison::to_json(self : DeltaComparison) -> String {
  let builder = StringBuilder()
  builder <+ "{\"left_size\":\{self.left_size},"
  builder <+ "\"right_size\":\{self.right_size},"
  builder <+ "\"size_difference\":\{self.size_difference},"
  builder <+ "\"left_instructions\":\{self.left_instructions},"
  builder <+ "\"right_instructions\":\{self.right_instructions},"
  builder <+ "\"instruction_difference\":\{self.instruction_difference},"
  builder <+ "\"same_target_size\":"
  append_json_bool(builder, self.same_target_size)
  builder <+ ",\"same_window_count\":"
  append_json_bool(builder, self.same_window_count)
  builder <+ ",\"same_instruction_mix\":"
  append_json_bool(builder, self.same_instruction_mix)
  builder <+ "}"
  builder.to_string()
}

///|
/// Renders a checked error as compact valid JSON for embedding in tools.
pub fn VcdiffError::to_json(self : VcdiffError) -> String {
  let builder = StringBuilder()
  builder <+ "{\"code\":"
  builder.write_string(quoted_json(self.code()))
  builder <+ ",\"message\":"
  builder.write_string(quoted_json(self.message()))
  builder <+ ",\"offset\":\{self.offset()}}"
  builder.to_string()
}