/**
 * This file is part of Eclipse Steady.
 *
 * Licensed 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.
 *
 * SPDX-License-Identifier: Apache-2.0
 * SPDX-FileCopyrightText: Copyright (c) 2018-2020 SAP SE or an SAP affiliate company and Eclipse Steady contributors
 */
package org.eclipse.steady.backend.rest;

import org.eclipse.steady.backend.repo.BugRepositoryImpl;
import org.eclipse.steady.backend.util.ReferenceUpdater;
import org.eclipse.steady.shared.util.Constants;
import org.eclipse.steady.shared.util.VulasConfiguration;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.security.SecurityScheme.In;

/**
 * <p>MainController class.</p>
 */
@Configuration
@ComponentScan({
  "org.eclipse.steady.backend.component,org.eclipse.steady.backend.rest,org.eclipse.steady.backend.util"
})
@EnableAutoConfiguration
@EnableCaching
@EntityScan({
  "org.eclipse.steady.backend.model"
}) // So that managed entities in the model package are discovered
@EnableJpaRepositories({
  "org.eclipse.steady.backend.repo"
}) // So that repos in the repo package are discovered
public class MainController extends SpringBootServletInitializer {

  /**
   * TODO: Autom. switch off in production.
   * Registers the Servlet for the H2 Web console, which allows checking DB content.
   * Connect using localhost:xxxx/backend/console (JDBC URL jdbc:h2:mem:testdb)
   * @return
   */
  /*@Bean
  @Profile("test")
     ServletRegistrationBean h2servletRegistration(){
         final ServletRegistrationBean registrationBean = new ServletRegistrationBean( new WebServlet());
         registrationBean.addUrlMappings("/console/*");
         registrationBean.addInitParameter("webAllowOthers", "true");
         return registrationBean;
     }*/

  /**
   * Used by custom repository methods to replace nested transient entities by managed ones.
   * See, for instance, {@link BugRepositoryImpl#customSave(org.eclipse.steady.backend.model.Bug)}.
   * @return
   */
  @Bean
  ReferenceUpdater refUpdater() {
    return new ReferenceUpdater();
  }

  /**
   * Returns the API info for Swagger.
   * @return a {@link io.swagger.v3.oas.models.OpenAPI} object.
   */
  @Bean
  public OpenAPI customOpenAPI() {
    return new OpenAPI()
        .components(
            new Components()
                .addSecuritySchemes(
                    "tenant",
                    new SecurityScheme()
                        .type(SecurityScheme.Type.APIKEY)
                        .in(In.HEADER)
                        .name(Constants.HTTP_TENANT_HEADER))
                .addSecuritySchemes(
                    "space",
                    new SecurityScheme()
                        .type(SecurityScheme.Type.APIKEY)
                        .in(In.HEADER)
                        .name(Constants.HTTP_SPACE_HEADER)))
        .info(
            new Info()
                .title("Vulas REST API")
                .description("This is the REST API of Vulas")
                .version(
                    VulasConfiguration.getGlobal().getConfiguration().getString("shared.version")));
  }

  /**
   * <p>bugApi.</p>
   *
   * @return a {@link org.springdoc.core.GroupedOpenApi} object.
   */
  @Bean
  public GroupedOpenApi bugApi() {
    String paths[] = {"/bugs/**", "/coverage/**", "/cves/**"};
    return GroupedOpenApi.builder().setGroup("bug-api").pathsToMatch(paths).build();
  }

  /**
   * <p>userApi.</p>
   *
   * @return a {@link org.springdoc.core.GroupedOpenApi} object.
   */
  @Bean
  public GroupedOpenApi userApi() {
    String paths[] = {"/apps/**", "/hubIntegration/**", "/libs/**", "/libids/**", "/spaces/**"};
    return GroupedOpenApi.builder().setGroup("user-api").pathsToMatch(paths).build();
  }

  /**
   * <p>adminApi.</p>
   *
   * @return a {@link org.springdoc.core.GroupedOpenApi} object.
   */
  @Bean
  public GroupedOpenApi adminApi() {
    String paths[] = {"/configuration/**", "/tenants/**"};
    return GroupedOpenApi.builder().setGroup("admin-api").pathsToMatch(paths).build();
  }

  /**
   * Can be used to do some initialization at application startup, but does not do anything right now.
   *
   * @return a {@link org.springframework.http.converter.json.Jackson2ObjectMapperBuilder} object.
   */
  //	@Bean
  //	CommandLineRunner init() { return null; }

  @Bean
  public Jackson2ObjectMapperBuilder jacksonBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.defaultViewInclusion(true);
    // builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
    return builder;
  }

  //  The following bean is commented out because it contains the default
  //  values used anyway by @EnableCaching
  //  @Bean
  //  public CacheManager cacheManager() {
  //      return new ConcurrentMapCacheManager("bug");
  //  }

  /**
   * <p>main.</p>
   *
   * @param args an array of {@link java.lang.String} objects.
   */
  public static void main(String[] args) {
    SpringApplication.run(MainController.class, args);
  }

  /** {@inheritDoc} */
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(MainController.class);
  }
}
