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

import io.jooby.exception.MissingValueException;

/**
 * A stateful reader used at runtime to extract arguments from JSON-RPC parameters.
 *
 * <p>When a JSON-RPC client sends a request, it packs the arguments into the {@code params} field
 * as either an Array (positional) or an Object (named). This reader acts as a cursor or keyed
 * accessor over that structure. The Jooby Annotation Processor (APT) generates routing code that
 * calls the {@code next*()} methods on this interface sequentially, perfectly matching the
 * 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 to read numbers and booleans without ever boxing them into heap-allocated objects
 * like {@code Integer} or {@code Boolean}.
 *
 * <p>Because it may hold resources (depending on the JSON library implementation), it implements
 * {@link AutoCloseable} and must be closed after the final argument is read.
 */
public interface JsonRpcReader extends AutoCloseable {

  /**
   * Evaluates the next parameter to determine if it is a literal {@code null} or missing.
   *
   * @param name The logical name of the parameter being evaluated (used for named lookup or
   *     context).
   * @return {@code true} if the parameter is null or missing; {@code false} otherwise.
   */
  boolean nextIsNull(String name);

  /**
   * Asserts that the next parameter 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 parameter evaluates to null or is missing.
   */
  default void requireNext(String name) {
    if (nextIsNull(name)) {
      throw new MissingValueException(name);
    }
  }

  /**
   * Reads the next parameter 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 parameter 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 parameter as a primitive boolean.
   *
   * @param name The logical name of the parameter.
   * @return The extracted boolean value.
   */
  boolean nextBoolean(String name);

  /**
   * Reads the next parameter 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 parameter as a String.
   *
   * @param name The logical name of the parameter.
   * @return The extracted String value, or {@code null} if the parameter is a JSON null.
   */
  String nextString(String name);

  /**
   * Reads the next parameter (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 via the provided {@link JsonRpcDecoder}.
   *
   * @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 parameter is a JSON null.
   */
  <T> T nextObject(String name, JsonRpcDecoder<T> decoder);
}
