// Correlation ID — trace a request across multiple log entries

///|
pub(all) struct CorrelationId {
  id : String
  sequence : Int
}

///|
pub fn CorrelationId::new(id : String) -> CorrelationId {
  CorrelationId::{ id, sequence: 0 }
}

// Generate a unique-ish ID from a prefix and sequence number

///|
pub fn CorrelationId::generate(prefix : String, seq : Int) -> CorrelationId {
  CorrelationId::{ id: prefix + "-" + seq.to_string(), sequence: 0 }
}

///|
pub fn CorrelationId::next(self : CorrelationId) -> CorrelationId {
  CorrelationId::{ ..self, sequence: self.sequence + 1 }
}

///|
pub fn CorrelationId::to_field(
  self : CorrelationId,
  key : String,
) -> (String, String) {
  let value = self.id + "[" + self.sequence.to_string() + "]"
  (key, value)
}

// Attach correlation ID to log fields

///|
pub fn with_correlation(
  fields : Array[(String, String)],
  corr : CorrelationId,
  key : String,
) -> Array[(String, String)] {
  let new_fields = fields
  new_fields.push(corr.to_field(key))
  new_fields
}

// RequestContext — combines LogContext + CorrelationId + Span tracking

///|
pub(all) struct RequestContext {
  context : LogContext
  correlation : CorrelationId
  logger : Logger
}

///|
pub fn RequestContext::new(
  logger : Logger,
  request_id : String,
) -> RequestContext {
  let corr = CorrelationId::new(request_id)
  let ctx = LogContext::new().add("trace_id", request_id)
  RequestContext::{ context: ctx, correlation: corr, logger }
}

///|
pub fn RequestContext::with_field(
  self : RequestContext,
  key : String,
  value : String,
) -> RequestContext {
  RequestContext::{ ..self, context: self.context.add(key, value) }
}

///|
pub fn RequestContext::info(
  self : RequestContext,
  msg : String,
  fields : Array[(String, String)],
) -> RequestContext {
  let next_corr = self.correlation.next()
  let merged = self.context.merge(fields)
  let with_corr = with_correlation(merged, next_corr, "corr_id")
  let new_logger = self.logger.info(msg, with_corr)
  RequestContext::{ ..self, correlation: next_corr, logger: new_logger }
}

///|
pub fn RequestContext::warn(
  self : RequestContext,
  msg : String,
  fields : Array[(String, String)],
) -> RequestContext {
  let next_corr = self.correlation.next()
  let merged = self.context.merge(fields)
  let with_corr = with_correlation(merged, next_corr, "corr_id")
  let new_logger = self.logger.warn(msg, with_corr)
  RequestContext::{ ..self, correlation: next_corr, logger: new_logger }
}

///|
pub fn RequestContext::error(
  self : RequestContext,
  msg : String,
  fields : Array[(String, String)],
) -> RequestContext {
  let next_corr = self.correlation.next()
  let merged = self.context.merge(fields)
  let with_corr = with_correlation(merged, next_corr, "corr_id")
  let new_logger = self.logger.error(msg, with_corr)
  RequestContext::{ ..self, correlation: next_corr, logger: new_logger }
}

///|
pub fn RequestContext::finish(self : RequestContext) -> Logger {
  self.logger.info("Request complete", [
    ("trace_id", self.correlation.id),
    ("total_steps", self.correlation.sequence.to_string()),
  ])
}