///|
/// One recorded command -> response interaction of an SMTP session.
pub struct SmtpStep {
  command : String
  code : Int
  text : String
  duration_ms : Int64
} derive(Eq, Debug)

///|
/// Redact a command for the trace: AUTH payloads (which contain credentials)
/// are never recorded (MM_SMTP_001 security model, section 15).
pub fn redact_command(command : String) -> String {
  let upper = command.to_upper()
  if upper.has_prefix("AUTH PLAIN ") {
    "AUTH PLAIN [REDACTED]"
  } else if upper == "AUTH LOGIN" || upper.has_prefix("AUTH LOGIN ") {
    "AUTH LOGIN"
  } else if upper == "AUTH CRAM-MD5" || upper.has_prefix("AUTH CRAM-MD5 ") {
    "AUTH CRAM-MD5"
  } else {
    command
  }
}

///|
/// A full diagnostic report of an SMTP session: every step, the negotiated
/// capabilities, the auth mechanism used, and any diagnostics accumulated.
pub struct SmtpTrace {
  steps : Array[SmtpStep]
  mut capabilities : SmtpCaps
  mut auth_used : String
  mut final_code : Int
  diagnostics : Array[String]
} derive(Eq, Debug)

///|
pub fn SmtpTrace::empty() -> SmtpTrace {
  {
    steps: [],
    capabilities: SmtpCaps::empty(),
    auth_used: "",
    final_code: 0,
    diagnostics: [],
  }
}

///|
pub fn SmtpTrace::steps(self : SmtpTrace) -> Array[SmtpStep] {
  self.steps
}

///|
pub fn SmtpTrace::capabilities(self : SmtpTrace) -> SmtpCaps {
  self.capabilities
}

///|
pub fn SmtpTrace::auth_used(self : SmtpTrace) -> String {
  self.auth_used
}

///|
pub fn SmtpTrace::final_code(self : SmtpTrace) -> Int {
  self.final_code
}

///|
pub fn SmtpTrace::diagnostics(self : SmtpTrace) -> Array[String] {
  self.diagnostics
}

///|
pub fn SmtpTrace::add_step(
  self : SmtpTrace,
  command : String,
  reply : ServerReply,
  duration_ms : Int64,
) -> Unit {
  self.steps.push({
    command: redact_command(command),
    code: reply.code,
    text: reply.text,
    duration_ms,
  })
}

///|
pub fn SmtpTrace::add_diagnostic(self : SmtpTrace, message : String) -> Unit {
  self.diagnostics.push(message)
}

///|
/// Render the trace as a readable transcript, e.g. for `moonmail explain`.
pub fn SmtpTrace::render(self : SmtpTrace) -> String {
  let buf = Buffer::Buffer()
  buf.write_string_utf16le("SmtpTrace {\n")
  buf.write_string_utf16le(
    "  capabilities: AUTH=[\{self.capabilities.auth.join(",")}] 8BITMIME=\{self.capabilities.has_8bitmime} SMTPUTF8=\{self.capabilities.has_smtputf8}\n",
  )
  if self.auth_used != "" {
    buf.write_string_utf16le("  auth: \{self.auth_used}\n")
  }
  for step in self.steps {
    buf.write_string_utf16le("  \{step.command} -> \{step.code} \{step.text}\n")
  }
  for d in self.diagnostics {
    buf.write_string_utf16le("  diag: \{d}\n")
  }
  buf.write_string_utf16le("  final_code: \{self.final_code}\n")
  buf.write_string_utf16le("}")
  buf.to_string()
}