content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.cassandra.sidecar.handlers;
  
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import com.google.inject.Singleton;
  import io.netty.handler.codec.http.HttpResponseStatus;
  import io.vertx.core.Future;
  import io.vertx.core.Handler;
  import io.vertx.core.Vertx;
  import io.vertx.core.buffer.Buffer;
  import io.vertx.core.file.FileSystem;
  import io.vertx.ext.web.RoutingContext;
  
  import static org.apache.cassandra.sidecar.utils.HttpExceptions.wrapHttpException;
  
  /**
   * Handler that serves the OpenAPI specification
   *
   * <p>This handler serves the OpenAPI specification generated by the Gradle generateOpenApiSpec task
   * which processes JAX-RS/MicroProfile annotations to create comprehensive API documentation.
   */
  @Singleton
  public class OpenApiHandler implements Handler<RoutingContext>
  {
      private static final Logger LOGGER = LoggerFactory.getLogger(OpenApiHandler.class);
  
      @Override
      public void handle(RoutingContext context)
      {
          boolean isYaml = isYamlRequest(context);
          String contentType = isYaml ? "application/yaml" : "application/json";
          String fileName = isYaml ? "openapi.yaml" : "openapi.json";
  
          loadGeneratedOpenApiSpec(context.vertx(), fileName)
          .onSuccess(buffer -> context.response()
                                      .putHeader("Content-Type", contentType)
                                      .end(buffer))
          .onFailure(throwable -> {
              LOGGER.error("Unable to read specification", throwable);
              context.fail(wrapHttpException(HttpResponseStatus.NOT_FOUND, "Unable to find specification"));
          });
      }
  
      /**
       * Loads the generated OpenAPI specification from resources or build output
       *
       * @param vertx    the vertx instance
       * @param fileName the name of the file to load
       * @return a future with the contents of the file
       */
      private Future<Buffer> loadGeneratedOpenApiSpec(Vertx vertx, String fileName)
      {
          FileSystem fileSystem = vertx.fileSystem();
          return fileSystem
                 // Attempt reading the spec from resource
                 .readFile("openapi/" + fileName)
                 // Then attempt from project root
                 .recover(cause -> fileSystem.readFile("server/build/resources/main/openapi/" + fileName))
                 // // Then attempt from server directory
                 .recover(cause -> fileSystem.readFile("build/resources/main/openapi/" + fileName))
                 // Alternative relative path
                 .recover(cause -> fileSystem.readFile("../server/build/resources/main/openapi/" + fileName));
      }
  
      /**
       * @return whether the request is for YAML format based on path or Accept header
       */
      private boolean isYamlRequest(RoutingContext context)
      {
          String path = context.request().path();
          if (path != null && path.endsWith(".yaml"))
          {
              return true;
          }
  
          String acceptHeader = context.request().getHeader("Accept");
          return acceptHeader != null && acceptHeader.contains("application/yaml");
      }
  }
  