package com.railway.web.core.config;

import com.railway.common.config.RailwayConfig;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ParameterType;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * Swagger2的接口配置
 *
 * @author railway
 */
@Configuration
public class SwaggerConfig {

  /**
   * 系统基础配置
   */
  private final RailwayConfig railwayConfig;

  /**
   * 是否开启swagger
   */
  @Value("${swagger.enabled}")
  private boolean enabled;

  /**
   * 设置请求的统一前缀
   */
  @Value("${swagger.pathMapping}")
  private String pathMapping;

  public SwaggerConfig(RailwayConfig railwayConfig) {
    this.railwayConfig = railwayConfig;
  }

  /**
   * 安全模式，这里指定token通过Authorization头请求头传递
   */
  private List<SecurityScheme> securitySchemes() {
    List<SecurityScheme> apiKeyList = new ArrayList<>();
    apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
    return apiKeyList;
  }

  /**
   * 安全上下文
   */
  private List<SecurityContext> securityContexts() {
    List<SecurityContext> securityContexts = new ArrayList<>();
    securityContexts.add(
        SecurityContext.builder()
            .securityReferences(defaultAuth())
            .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
            .build());
    return securityContexts;
  }

  /**
   * 默认的安全上引用
   */
  private List<SecurityReference> defaultAuth() {
    AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
    AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
    authorizationScopes[0] = authorizationScope;
    List<SecurityReference> securityReferences = new ArrayList<>();
    securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
    return securityReferences;
  }

  /**
   * 全部接口
   *
   * @return Docket
   */
  @Bean
  public Docket wholeDocket(Environment environment) {
    return getDocket(environment, "000.全部", "供电生产管理系统服务", "供电生产管理系统", null);
  }

  /**
   * 系统管理分组接口
   *
   * @return Docket
   */
  @Bean
  public Docket systemDocket(Environment environment) {
    return getDocket(environment, "001.系统管理", "系统管理", "系统管理", new String[]{
        "/register",
        "/login",
        "/getInfo",
        "/system/dept/.*",
        "/system/dict/type/.*",
        "/system/dict/data/.*",
        "/system/menu/.*",
        "/system/user/profile/.*",
        "/system/role/.*",
        "/system/user/.*",
        "/monitor/logininfor/.*",
        "/monitor/operlog/.*",
        "/captchaImage",
        "/common/.*",
    });
  }

  /**
   * 基础信息分组接口
   *
   * @return Docket
   */
  @Bean
  public Docket baseInfoDocket(Environment environment) {
    return getDocket(environment, "002.基础信息", "基础信息", "基础信息", new String[]{
        "/login",
        "/business/catenary/bus/line/.*",
        "/business/catenary/bus/station/.*",
        "/business/catenary/bus/substation/.*",
        "/business/catenary/bus/blq/.*",
        "/business/catenary/bus/dmcgyq/.*",
        "/business/catenary/bus/fdfxjyq/.*",
        "/business/catenary/bus/fjxgmd/.*",
        "/business/catenary/bus/glkg/.*",
        "/business/catenary/bus/jcxc/.*",
        "/business/catenary/bus/sdtz/.*",
        "/business/catenary/bus/wjcxc/.*",
        "/business/catenary/bus/zzdzxx/.*",
    });
  }

  /**
   * 检查表分组接口
   *
   * @return Docket
   */
  @Bean
  public Docket jcbDocket(Environment environment) {
    return getDocket(environment, "003.检查表", "检查表", "检查表", new String[]{
        "/login",
        "/business/catenary/bus/jcb/.*",
    });
  }

  /**
   * 检查表分组接口
   *
   * @return Docket
   */
  @Bean
  public Docket jcebDocket(Environment environment) {
    return getDocket(environment, "004.检测表", "检测表", "检测表", new String[]{
        "/login",
        "/business/catenary/bus/jceb/.*",
    });
  }

  /**
   * 九防台账分组接口
   *
   * @return Docket
   */
  @Bean
  public Docket preventDocket(Environment environment) {
    return getDocket(environment, "005.九防台账", "九防台账", "九防台账", new String[]{
        "/login",
        "/business/catenary/bus/prevent/.*",
        "/business/baseinfo/base/prevent/.*",
    });
  }

  /**
   * 安全工具
   *
   * @return Docket
   */
  @Bean
  public Docket saftoolDocket(Environment environment) {
    return getDocket(environment, "006.安全工具", "安全工具", "安全工具", new String[]{
            "/login",
            "/business/safetool/.*"
    });
  }

  /**
   * 创建API
   */
  @Bean
  public Docket createRestApi() {
    return new Docket(DocumentationType.OAS_30)
        // 是否启用Swagger
        .enable(enabled)
        // 用来创建该API的基本信息，展示在文档的页面中（自定义展示的信息）
        .apiInfo(apiInfo())
        // 设置哪些接口暴露给Swagger展示
        .select()
        // 扫描所有有注解的api，用这种方式更灵活
        .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
        // 扫描指定包中的swagger注解
        // .apis(RequestHandlerSelectors.basePackage("com.railway.project.tool.swagger"))
        // 扫描所有 .apis(RequestHandlerSelectors.any())
        .paths(PathSelectors.any())
        .build()
        /* 设置安全模式，swagger可以设置访问token */
        .securitySchemes(securitySchemes())
        .securityContexts(securityContexts())
        .pathMapping(pathMapping);
  }

  /**
   * 设置分组信息
   *
   * @param groupName 组名
   * @param apiName apiName
   * @param apiDesc apiDesc
   * @param paths 正则路径匹配
   * @return docket
   */
  private Docket getDocket(Environment environment, String groupName, String apiName,
      String apiDesc, String[] paths) {

    // 设置显示 swagger的环境
    Profiles profiles = Profiles.of("dev", "test", "local");

    boolean flag = environment.acceptsProfiles(profiles);

    List<RequestParameter> requestParameterList = new ArrayList<>();
    RequestParameter requestParameter = new RequestParameterBuilder()
        .name("Authorization")
        .description("模拟用户Token")
        .in(ParameterType.HEADER)
        .required(false)
        .build();
    requestParameterList.add(requestParameter);

    ApiSelectorBuilder apiSelectorBuilder = new Docket(DocumentationType.OAS_30)
        // 是否启用Swagger
        .enable(enabled)
        .apiInfo(apiInfo(apiName, apiDesc))
        .groupName(groupName)
        /* 设置安全模式，swagger可以设置访问token */
        .securitySchemes(securitySchemes())
        .securityContexts(securityContexts())
        .pathMapping(pathMapping)
        .select()
        // 扫描所有有注解的api，用这种方式更灵活
        .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class));

    if (paths == null) {
      apiSelectorBuilder.paths(PathSelectors.any());
    } else {
      StringBuilder pathRegex = new StringBuilder();
      for (String path : paths) {
        pathRegex.append("(").append(path).append(")|");
      }
      apiSelectorBuilder.paths(PathSelectors.regex(pathRegex.substring(0, pathRegex.length() - 1)));
    }

    return apiSelectorBuilder.build()
        .globalRequestParameters(requestParameterList)
        .ignoredParameterTypes(HttpServletResponse.class, HttpServletRequest.class)
        .enable(flag);
  }


  /**
   * 添加摘要信息
   */
  private ApiInfo apiInfo() {
    // 用ApiInfoBuilder进行定制
    return apiInfo("供电生产管理系统", "供电生产管理系统API");
  }

  /**
   * swagger 标题信息
   *
   * @param title 标题
   * @param description 描述
   * @return ApiInfo
   */
  private ApiInfo apiInfo(String title, String description) {
    String url = "http://railway-web.iamsee.com/";
    String email = "railway@railway.com";
    return new ApiInfoBuilder()
        .title(title)
        .description(description)
        .contact(new Contact(railwayConfig.getName(), url, email))
        .version("版本号:" + railwayConfig.getVersion())
        .build();
  }

}
