///|
/// Pure execution helpers behind the command-line entry point.
pub(all) struct GifCliResult {
  command : GifCommand
  bytes : Bytes?
  animation : Animation?
  report : GifDocumentReport?
  messages : Array[String]
} derive(Debug)

///|
pub fn GifCliResult::command(self : GifCliResult) -> GifCommand {
  self.command
}

///|
pub fn GifCliResult::bytes(self : GifCliResult) -> Bytes? {
  self.bytes
}

///|
pub fn GifCliResult::animation(self : GifCliResult) -> Animation? {
  self.animation
}

///|
pub fn GifCliResult::report(self : GifCliResult) -> GifDocumentReport? {
  self.report
}

///|
pub fn GifCliResult::messages(self : GifCliResult) -> ArrayView[String] {
  self.messages[:]
}

///|
/// Execute an inspect/decode request on an in-memory GIF.
pub fn run_cli_request(request : GifCliRequest, data : Bytes) -> GifCliResult {
  let messages : Array[String] = []
  match request.command {
    Inspect =>
      try {
        let report = report_gif(data)
        messages.push(report.summary())
        GifCliResult::{
          command: Inspect,
          bytes: None,
          animation: None,
          report: Some(report),
          messages,
        }
      } catch {
        _ =>
          GifCliResult::{
            command: Inspect,
            bytes: None,
            animation: None,
            report: None,
            messages: [explain_gif_error(data)],
          }
      } noraise {
        _ =>
          GifCliResult::{
            command: Inspect,
            bytes: None,
            animation: None,
            report: None,
            messages: ["inspect failed"],
          }
      }
    Decode =>
      GifCliResult::{
        command: Decode,
        bytes: None,
        animation: decode_checked(data),
        report: None,
        messages,
      }
    _ =>
      GifCliResult::{
        command: request.command,
        bytes: None,
        animation: None,
        report: None,
        messages: ["command requires an animation source"],
      }
  }
}

///|
/// Execute an encode request on an animation and attach a structural report.
pub fn run_encode_request(
  request : GifCliRequest,
  animation : Animation,
) -> GifCliResult {
  let messages : Array[String] = []
  let plan : GifCliPlan? = try
    Some(make_cli_plan(request, Some(animation)))
  catch {
    _ => None
  } noraise {
    _ => None
  }
  match plan {
    None =>
      GifCliResult::{
        command: Encode,
        bytes: None,
        animation: Some(animation),
        report: None,
        messages: ["unable to construct encode plan"],
      }
    Some(value) => {
      let outcome = encode_checked(animation, value.encode_options())
      match outcome.bytes() {
        None =>
          GifCliResult::{
            command: Encode,
            bytes: None,
            animation: Some(animation),
            report: None,
            messages: ["encode failed"],
          }
        Some(bytes) => {
          let report = try Some(report_gif(bytes)) catch {
            _ => None
          } noraise {
            _ => None
          }
          GifCliResult::{
            command: Encode,
            bytes: Some(bytes),
            animation: Some(animation),
            report,
            messages,
          }
        }
      }
    }
  }
}

///|
/// Run a deterministic benchmark request without filesystem access.
pub fn run_benchmark_request(
  request : GifCliRequest,
) -> GifCliResult raise GifError {
  let workload = BenchmarkWorkload::default()
  let benchmark = run_benchmark(workload)
  GifCliResult::{
    command: request.command,
    bytes: None,
    animation: None,
    report: None,
    messages: [benchmark.summary()],
  }
}