/*
 * Jooby https://jooby.io
 * Apache License Version 2.0 https://jooby.io/LICENSE.txt
 * Copyright 2014 Edgar Espina
 */
package io.jooby.rpc.trpc;

import io.jooby.exception.MissingValueException;

/**
 * A stateful, sequential reader used at runtime to extract arguments from a tRPC network payload.
 *
 * <p>When a tRPC client sends a request for a multi-argument method, it packs the arguments into a
 * JSON array (a tuple). This reader acts as a cursor over that array. The Jooby Annotation
 * Processor (APT) generates routing code that calls the {@code next*()} methods on this interface
 * sequentially, perfectly matching the order of parameters in the target Java method.
 *
 * <p><b>Zero-Boxing Performance:</b>
 *
 * <p>To maximize throughput, this interface provides dedicated methods for extracting primitive
 * types (e.g., {@link #nextInt(String)}, {@link #nextBoolean(String)}). This allows the underlying
 * JSON parser (like Jackson or AvajeJsonb) to read numbers and booleans directly off the byte
 * stream without ever boxing them into heap-allocated objects like {@code Integer} or {@code
 * Boolean}.
 *
 * <p>Because it holds resources (like an open {@code JsonParser}), it implements {@link
 * AutoCloseable} and must be closed after the final argument is read.
 */
public interface TrpcReader extends AutoCloseable {

  /**
   * Peeks at the next token in the JSON stream to determine if it is a literal {@code null}.
   *
   * @param name The logical name of the parameter being evaluated (used for context or error
   *     reporting).
   * @return {@code true} if the next token is null; {@code false} otherwise.
   */
  boolean nextIsNull(String name);

  /**
   * Asserts that the next token in the sequence is not null.
   *
   * <p>This is a fast-fail mechanism generated by the APT for non-nullable primitive arguments
   * (e.g., {@code int}, {@code double}) or explicitly required parameters.
   *
   * @param name The logical name of the parameter.
   * @throws MissingValueException If the next token evaluates to null.
   */
  default void requireNext(String name) {
    if (nextIsNull(name)) {
      throw new MissingValueException(name);
    }
  }

  /**
   * Reads the next token in the stream as a primitive 32-bit integer.
   *
   * @param name The logical name of the parameter.
   * @return The extracted integer value.
   */
  int nextInt(String name);

  /**
   * Reads the next token in the stream as a primitive 64-bit integer.
   *
   * @param name The logical name of the parameter.
   * @return The extracted long value.
   */
  long nextLong(String name);

  /**
   * Reads the next token in the stream as a primitive boolean.
   *
   * @param name The logical name of the parameter.
   * @return The extracted boolean value.
   */
  boolean nextBoolean(String name);

  /**
   * Reads the next token in the stream as a primitive 64-bit floating-point number.
   *
   * @param name The logical name of the parameter.
   * @return The extracted double value.
   */
  double nextDouble(String name);

  /**
   * Reads the next token in the stream as a String.
   *
   * @param name The logical name of the parameter.
   * @return The extracted String value, or {@code null} if the token is a JSON null.
   */
  String nextString(String name);

  /**
   * Reads the next token (which may be a complex JSON object or array) and deserializes it using a
   * pre-resolved type decoder.
   *
   * <p>This method delegates the heavy lifting of mapping arbitrary JSON structures to the
   * underlying JSON engine (Jackson, Gson, etc.) via the provided {@link TrpcDecoder}.
   *
   * @param name The logical name of the parameter.
   * @param decoder The optimized decoder created during application startup to handle this specific
   *     type.
   * @param <T> The target Java type.
   * @return The fully deserialized Java object, or {@code null} if the token is a JSON null.
   */
  <T> T nextObject(String name, TrpcDecoder<T> decoder);
}
