/**
 * OpenAPI Petstore
 * This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
 *
 * The version of the OpenAPI document: 1.0.0
 * 
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

package org.openapitools.client.api;

import java.util.Objects;
import org.openapitools.client.ApiResponse;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.helidon.common.GenericType;
import io.helidon.common.http.MediaType;
import io.helidon.common.reactive.Single;
import io.helidon.config.Config;
import io.helidon.media.common.MediaSupport;

import io.helidon.media.jackson.JacksonSupport;
import io.helidon.webclient.WebClientRequestBuilder;
import io.helidon.webclient.WebClientResponse;

import org.openapitools.client.ApiClient;

import java.io.File;
import java.util.List;
import java.util.Map;
import org.openapitools.client.model.ModelApiResponse;
import org.openapitools.client.model.Pet;
import java.util.Set;
import java.util.ArrayList;
import org.openapitools.client.Pair;
import java.util.StringJoiner;
import io.helidon.webclient.WebClientRequestHeaders;

/**
 * OpenAPI Petstore
 *
 * <p>This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
 */
public class PetApiImpl implements PetApi {

  private final ApiClient apiClient;

  protected static final GenericType<Void> RESPONSE_TYPE_addPet = ResponseType.create(Void.class);
  protected static final GenericType<Void> RESPONSE_TYPE_deletePet = ResponseType.create(Void.class);
  protected static final GenericType<List<Pet>> RESPONSE_TYPE_findPetsByStatus = ResponseType.create(List.class, Pet.class);
  protected static final GenericType<List<Pet>> RESPONSE_TYPE_findPetsByTags = ResponseType.create(List.class, Pet.class);
  protected static final GenericType<Pet> RESPONSE_TYPE_getPetById = ResponseType.create(Pet.class);
  protected static final GenericType<Void> RESPONSE_TYPE_updatePet = ResponseType.create(Void.class);
  protected static final GenericType<Void> RESPONSE_TYPE_updatePetWithForm = ResponseType.create(Void.class);
  protected static final GenericType<ModelApiResponse> RESPONSE_TYPE_uploadFile = ResponseType.create(ModelApiResponse.class);
  protected static final GenericType<ModelApiResponse> RESPONSE_TYPE_uploadFileWithRequiredFile = ResponseType.create(ModelApiResponse.class);

  /**
   * Creates a new instance of PetApiImpl initialized with the specified {@link ApiClient}.
   *
   */
  public static PetApiImpl create(ApiClient apiClient) {
    return new PetApiImpl(apiClient);
  }

  protected PetApiImpl(ApiClient apiClient) {
    this.apiClient = apiClient;
  }

  @Override
  public ApiResponse<Void> addPet(Pet pet) {
    Objects.requireNonNull(pet, "Required parameter 'pet' not specified");
    WebClientRequestBuilder webClientRequestBuilder = addPetRequestBuilder(pet);
    return addPetSubmit(webClientRequestBuilder, pet);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the addPet operation.
   * Optional customization point for subclasses.
   *
   * @param pet Pet object that needs to be added to the store (required)
   * @return WebClientRequestBuilder for addPet
   */
  protected WebClientRequestBuilder addPetRequestBuilder(Pet pet) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("POST");

    webClientRequestBuilder.path("/pet");
    webClientRequestBuilder.contentType(MediaType.APPLICATION_JSON);
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the addPet operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param pet Pet object that needs to be added to the store (required)
   * @return {@code ApiResponse<Void>} for the submitted request
   */
  protected ApiResponse<Void> addPetSubmit(WebClientRequestBuilder webClientRequestBuilder, Pet pet) {
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit(pet);
    return ApiResponse.create(RESPONSE_TYPE_addPet, webClientResponse);
  }

  @Override
  public ApiResponse<Void> deletePet(Long petId, String apiKey) {
    Objects.requireNonNull(petId, "Required parameter 'petId' not specified");
    WebClientRequestBuilder webClientRequestBuilder = deletePetRequestBuilder(petId, apiKey);
    return deletePetSubmit(webClientRequestBuilder, petId, apiKey);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the deletePet operation.
   * Optional customization point for subclasses.
   *
   * @param petId Pet id to delete (required)
   * @param apiKey  (optional)
   * @return WebClientRequestBuilder for deletePet
   */
  protected WebClientRequestBuilder deletePetRequestBuilder(Long petId, String apiKey) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("DELETE");

    WebClientRequestHeaders headers = webClientRequestBuilder.headers();
    if (apiKey != null) {
      headers.put("api_key", apiKey);
    }

    String path = "/pet/{petId}"
            .replace("{petId}", ApiClient.urlEncode(petId.toString()));
    webClientRequestBuilder.path(path);
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the deletePet operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param petId Pet id to delete (required)
   * @param apiKey  (optional)
   * @return {@code ApiResponse<Void>} for the submitted request
   */
  protected ApiResponse<Void> deletePetSubmit(WebClientRequestBuilder webClientRequestBuilder, Long petId, String apiKey) {
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit();
    return ApiResponse.create(RESPONSE_TYPE_deletePet, webClientResponse);
  }

  @Override
  public ApiResponse<List<Pet>> findPetsByStatus(List<String> status) {
    Objects.requireNonNull(status, "Required parameter 'status' not specified");
    WebClientRequestBuilder webClientRequestBuilder = findPetsByStatusRequestBuilder(status);
    return findPetsByStatusSubmit(webClientRequestBuilder, status);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the findPetsByStatus operation.
   * Optional customization point for subclasses.
   *
   * @param status Status values that need to be considered for filter (required)
   * @return WebClientRequestBuilder for findPetsByStatus
   */
  protected WebClientRequestBuilder findPetsByStatusRequestBuilder(List<String> status) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("GET");

    List<Pair> queryParams = new ArrayList<>();
    queryParams.addAll(ApiClient.parameterToPairs("csv", "status", status));
    queryParams.forEach(p -> webClientRequestBuilder.queryParam(p.getName(), p.getValue()));

    webClientRequestBuilder.path("/pet/findByStatus");
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the findPetsByStatus operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param status Status values that need to be considered for filter (required)
   * @return {@code ApiResponse<List<Pet>>} for the submitted request
   */
  protected ApiResponse<List<Pet>> findPetsByStatusSubmit(WebClientRequestBuilder webClientRequestBuilder, List<String> status) {
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit();
    return ApiResponse.create(RESPONSE_TYPE_findPetsByStatus, webClientResponse);
  }

  @Deprecated
  @Override
  public ApiResponse<List<Pet>> findPetsByTags(Set<String> tags) {
    Objects.requireNonNull(tags, "Required parameter 'tags' not specified");
    WebClientRequestBuilder webClientRequestBuilder = findPetsByTagsRequestBuilder(tags);
    return findPetsByTagsSubmit(webClientRequestBuilder, tags);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the findPetsByTags operation.
   * Optional customization point for subclasses.
   *
   * @param tags Tags to filter by (required)
   * @return WebClientRequestBuilder for findPetsByTags
   */
  protected WebClientRequestBuilder findPetsByTagsRequestBuilder(Set<String> tags) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("GET");

    List<Pair> queryParams = new ArrayList<>();
    queryParams.addAll(ApiClient.parameterToPairs("csv", "tags", tags));
    queryParams.forEach(p -> webClientRequestBuilder.queryParam(p.getName(), p.getValue()));

    webClientRequestBuilder.path("/pet/findByTags");
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the findPetsByTags operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param tags Tags to filter by (required)
   * @return {@code ApiResponse<List<Pet>>} for the submitted request
   */
  protected ApiResponse<List<Pet>> findPetsByTagsSubmit(WebClientRequestBuilder webClientRequestBuilder, Set<String> tags) {
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit();
    return ApiResponse.create(RESPONSE_TYPE_findPetsByTags, webClientResponse);
  }

  @Override
  public ApiResponse<Pet> getPetById(Long petId) {
    Objects.requireNonNull(petId, "Required parameter 'petId' not specified");
    WebClientRequestBuilder webClientRequestBuilder = getPetByIdRequestBuilder(petId);
    return getPetByIdSubmit(webClientRequestBuilder, petId);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the getPetById operation.
   * Optional customization point for subclasses.
   *
   * @param petId ID of pet to return (required)
   * @return WebClientRequestBuilder for getPetById
   */
  protected WebClientRequestBuilder getPetByIdRequestBuilder(Long petId) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("GET");

    String path = "/pet/{petId}"
            .replace("{petId}", ApiClient.urlEncode(petId.toString()));
    webClientRequestBuilder.path(path);
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the getPetById operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param petId ID of pet to return (required)
   * @return {@code ApiResponse<Pet>} for the submitted request
   */
  protected ApiResponse<Pet> getPetByIdSubmit(WebClientRequestBuilder webClientRequestBuilder, Long petId) {
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit();
    return ApiResponse.create(RESPONSE_TYPE_getPetById, webClientResponse);
  }

  @Override
  public ApiResponse<Void> updatePet(Pet pet) {
    Objects.requireNonNull(pet, "Required parameter 'pet' not specified");
    WebClientRequestBuilder webClientRequestBuilder = updatePetRequestBuilder(pet);
    return updatePetSubmit(webClientRequestBuilder, pet);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the updatePet operation.
   * Optional customization point for subclasses.
   *
   * @param pet Pet object that needs to be added to the store (required)
   * @return WebClientRequestBuilder for updatePet
   */
  protected WebClientRequestBuilder updatePetRequestBuilder(Pet pet) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("PUT");

    webClientRequestBuilder.path("/pet");
    webClientRequestBuilder.contentType(MediaType.APPLICATION_JSON);
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the updatePet operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param pet Pet object that needs to be added to the store (required)
   * @return {@code ApiResponse<Void>} for the submitted request
   */
  protected ApiResponse<Void> updatePetSubmit(WebClientRequestBuilder webClientRequestBuilder, Pet pet) {
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit(pet);
    return ApiResponse.create(RESPONSE_TYPE_updatePet, webClientResponse);
  }

  @Override
  public ApiResponse<Void> updatePetWithForm(Long petId, String name, String status) {
    Objects.requireNonNull(petId, "Required parameter 'petId' not specified");
    WebClientRequestBuilder webClientRequestBuilder = updatePetWithFormRequestBuilder(petId, name, status);
    return updatePetWithFormSubmit(webClientRequestBuilder, petId, name, status);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the updatePetWithForm operation.
   * Optional customization point for subclasses.
   *
   * @param petId ID of pet that needs to be updated (required)
   * @param name Updated name of the pet (optional)
   * @param status Updated status of the pet (optional)
   * @return WebClientRequestBuilder for updatePetWithForm
   */
  protected WebClientRequestBuilder updatePetWithFormRequestBuilder(Long petId, String name, String status) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("POST");

    String path = "/pet/{petId}"
            .replace("{petId}", ApiClient.urlEncode(petId.toString()));
    webClientRequestBuilder.path(path);
    webClientRequestBuilder.contentType(MediaType.APPLICATION_FORM_URLENCODED);
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the updatePetWithForm operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param petId ID of pet that needs to be updated (required)
   * @param name Updated name of the pet (optional)
   * @param status Updated status of the pet (optional)
   * @return {@code ApiResponse<Void>} for the submitted request
   */
  protected ApiResponse<Void> updatePetWithFormSubmit(WebClientRequestBuilder webClientRequestBuilder, Long petId, String name, String status) {
    String formParams = new StringJoiner("&")
            .add("name=" + name)
            .add("status=" + status)
            .toString();
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit(formParams);
    return ApiResponse.create(RESPONSE_TYPE_updatePetWithForm, webClientResponse);
  }

  @Override
  public ApiResponse<ModelApiResponse> uploadFile(Long petId, String additionalMetadata, File _file) {
    Objects.requireNonNull(petId, "Required parameter 'petId' not specified");
    WebClientRequestBuilder webClientRequestBuilder = uploadFileRequestBuilder(petId, additionalMetadata, _file);
    return uploadFileSubmit(webClientRequestBuilder, petId, additionalMetadata, _file);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the uploadFile operation.
   * Optional customization point for subclasses.
   *
   * @param petId ID of pet to update (required)
   * @param additionalMetadata Additional data to pass to server (optional)
   * @param _file file to upload (optional)
   * @return WebClientRequestBuilder for uploadFile
   */
  protected WebClientRequestBuilder uploadFileRequestBuilder(Long petId, String additionalMetadata, File _file) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("POST");

    String path = "/pet/{petId}/uploadImage"
            .replace("{petId}", ApiClient.urlEncode(petId.toString()));
    webClientRequestBuilder.path(path);
    webClientRequestBuilder.contentType(MediaType.APPLICATION_FORM_URLENCODED);
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the uploadFile operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param petId ID of pet to update (required)
   * @param additionalMetadata Additional data to pass to server (optional)
   * @param _file file to upload (optional)
   * @return {@code ApiResponse<ModelApiResponse>} for the submitted request
   */
  protected ApiResponse<ModelApiResponse> uploadFileSubmit(WebClientRequestBuilder webClientRequestBuilder, Long petId, String additionalMetadata, File _file) {
    String formParams = new StringJoiner("&")
            .add("additionalMetadata=" + additionalMetadata)
            .add("file=" + _file)
            .toString();
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit(formParams);
    return ApiResponse.create(RESPONSE_TYPE_uploadFile, webClientResponse);
  }

  @Override
  public ApiResponse<ModelApiResponse> uploadFileWithRequiredFile(Long petId, File requiredFile, String additionalMetadata) {
    Objects.requireNonNull(petId, "Required parameter 'petId' not specified");
    Objects.requireNonNull(requiredFile, "Required parameter 'requiredFile' not specified");
    WebClientRequestBuilder webClientRequestBuilder = uploadFileWithRequiredFileRequestBuilder(petId, requiredFile, additionalMetadata);
    return uploadFileWithRequiredFileSubmit(webClientRequestBuilder, petId, requiredFile, additionalMetadata);
  }

  /**
   * Creates a {@code WebClientRequestBuilder} for the uploadFileWithRequiredFile operation.
   * Optional customization point for subclasses.
   *
   * @param petId ID of pet to update (required)
   * @param requiredFile file to upload (required)
   * @param additionalMetadata Additional data to pass to server (optional)
   * @return WebClientRequestBuilder for uploadFileWithRequiredFile
   */
  protected WebClientRequestBuilder uploadFileWithRequiredFileRequestBuilder(Long petId, File requiredFile, String additionalMetadata) {
    WebClientRequestBuilder webClientRequestBuilder = apiClient.webClient()
            .method("POST");

    String path = "/fake/{petId}/uploadImageWithRequiredFile"
            .replace("{petId}", ApiClient.urlEncode(petId.toString()));
    webClientRequestBuilder.path(path);
    webClientRequestBuilder.contentType(MediaType.APPLICATION_FORM_URLENCODED);
    webClientRequestBuilder.accept(MediaType.APPLICATION_JSON);

    return webClientRequestBuilder;
  }

  /**
   * Initiates the request for the uploadFileWithRequiredFile operation.
   * Optional customization point for subclasses.
   *
   * @param webClientRequestBuilder the request builder to use for submitting the request
   * @param petId ID of pet to update (required)
   * @param requiredFile file to upload (required)
   * @param additionalMetadata Additional data to pass to server (optional)
   * @return {@code ApiResponse<ModelApiResponse>} for the submitted request
   */
  protected ApiResponse<ModelApiResponse> uploadFileWithRequiredFileSubmit(WebClientRequestBuilder webClientRequestBuilder, Long petId, File requiredFile, String additionalMetadata) {
    String formParams = new StringJoiner("&")
            .add("additionalMetadata=" + additionalMetadata)
            .add("requiredFile=" + requiredFile)
            .toString();
    Single<WebClientResponse> webClientResponse = webClientRequestBuilder.submit(formParams);
    return ApiResponse.create(RESPONSE_TYPE_uploadFileWithRequiredFile, webClientResponse);
  }

}
