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.camel.quarkus.component.fhir.it;
  
  import java.time.Duration;
  import java.util.Collections;
  import java.util.Map;
  
  import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
  import org.apache.camel.quarkus.component.fhir.it.util.FhirTestHelper;
  import org.apache.camel.util.CollectionHelper;
  import org.eclipse.microprofile.config.ConfigProvider;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.testcontainers.containers.GenericContainer;
  import org.testcontainers.containers.wait.strategy.Wait;
  
  public class FhirTestResource implements QuarkusTestResourceLifecycleManager {
      private static final Logger LOGGER = LoggerFactory.getLogger(FhirTestResource.class);
      private static final String FHIR_DSTU_CONTEXT_PATH = "/hapi-fhir-jpaserver/fhir";
      private static final String FHIR_R_CONTEXT_PATH = "/fhir";
      private static final int CONTAINER_PORT = 8080;
  
      private FhirVersion fhirVersion;
      private GenericContainer<?> container;
  
      @Override
      public void init(Map<String, String> initArgs) {
          this.fhirVersion = FhirVersion.valueOf(initArgs.get("fhirVersion"));
      }
  
      @Override
      public Map<String, String> start() {
          if (this.fhirVersion == null) {
              return Collections.emptyMap();
          }
  
          if (!FhirTestHelper.isFhirVersionEnabled(fhirVersion.name())) {
              LOGGER.info("FHIR version {} is disabled. No hapi test container will be started for it.",
                      fhirVersion.simpleVersion());
              return Collections.emptyMap();
          }
  
          if (this.fhirVersion.equals(FhirVersion.DSTU2_1)) {
              // TODO: https://github.com/hapifhir/hapi-fhir-jpaserver-starter/issues/335
              // Return a fictional host to allow the application to start, which allows a minimal check that native mode can work
              return Map.of(String.format("camel.fhir.%s.test-url", fhirVersion.simpleVersion()), "http://localhost:8080");
          }
  
          try {
              LOGGER.info("FHIR version {} is enabled. Starting hapi test container for it.", fhirVersion.simpleVersion());
              String imageName = fhirVersion.getContainerImageName();
              container = new GenericContainer<>(imageName)
                      .withExposedPorts(CONTAINER_PORT)
                      .withEnv(fhirVersion.getFhirContainerVersionEnvVarName(), fhirVersion.getFhirContainerVersionEnvVarValue())
                      .withEnv("hapi.fhir.allow_multiple_delete", "true")
                      .withEnv("hapi.fhir.reuse_cached_search_results_millis", "-1")
                      .waitingFor(Wait.forHttp(fhirVersion.getHealthEndpointPath()).withStartupTimeout(Duration.ofMinutes(5)));
  
              container.start();
  
              return CollectionHelper.mapOf(
                      String.format("camel.fhir.%s.test-url", fhirVersion.simpleVersion()),
                      fhirVersion.getServerUrl(container.getHost(), container.getMappedPort(CONTAINER_PORT)));
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  
      @Override
      public void stop() {
          try {
              if (container != null) {
                  container.stop();
              }
          } catch (Exception e) {
              // ignored
          }
      }
  
      enum FhirVersion {
          DSTU2(FHIR_DSTU_CONTEXT_PATH),
          DSTU2_HL7ORG(FHIR_DSTU_CONTEXT_PATH),
          DSTU2_1(FHIR_DSTU_CONTEXT_PATH),
          DSTU3(FHIR_DSTU_CONTEXT_PATH),
          R4(FHIR_R_CONTEXT_PATH),
          R5(FHIR_R_CONTEXT_PATH);
  
          private final String contextPath;
  
          FhirVersion(String contextPath) {
              this.contextPath = contextPath;
          }
  
          public String simpleVersion() {
              return this.name().toLowerCase();
          }
  
          public String getFhirContainerVersionEnvVarName() {
              if (contextPath.equals(FHIR_DSTU_CONTEXT_PATH)) {
                  return "HAPI_FHIR_VERSION";
              }
              return "hapi.fhir.fhir_version";
          }
  
          public String getFhirContainerVersionEnvVarValue() {
              // Cannot pass DSTU2_HL7ORG as the version to the mock server. However, it is analogous to DSTU2 anyway
              if (this == DSTU2_HL7ORG) {
                  return DSTU2.name();
              }
              return this.name();
          }
  
          public String getContextPath() {
              return contextPath;
          }
  
          public String getContainerImageName() {
              String imageProperty = "fhir.container.image";
              if (name().contains("DSTU")) {
                  imageProperty = "fhir-dstu.container.image";
              }
              return ConfigProvider.getConfig().getValue(imageProperty, String.class);
          }
  
          public String getServerUrl(String host, int port) {
              return String.format("http://%s:%d%s", host, port, getContextPath());
          }
  
          public String getHealthEndpointPath() {
              return String.format("%s/metadata", getContextPath());
          }
      }
  }
  