package com.artfess.base.conf;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.artfess.base.annotation.ApiGroup;
import org.springframework.beans.factory.annotation.Value;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;


import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.VendorExtension;
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;

/**
 * Swagger配置辅助方法基础类
 * @author mikel
 */
public abstract class SwaggerConfigHelper implements WebMvcConfigurer {

	@Value("${spring.profiles.title}")
	private String title;
	@Value("${spring.profiles.description}")
	private String description;
	@Value("${spring.profiles.version}")
	private String version;
	
	/**
	 * 根据分组构建完整的API注册信息
	 * @param apiGroupName
	 * @param apiGroupKey
	 * @return
	 */
	public Docket buildProductApi(String apiGroupName, String apiGroupKey) {
		Docket docket = buildDocket(apiGroupName).apiInfo(buildBaseProductApiInfo());
		ApiSelectorBuilder builder = buildApiForGroupKey(docket, apiGroupKey);
		return buildApiSecurityAuth(builder);
	}
	/**
	 * 根据分组名创建Docket
	 * @param apiGroupName
	 * @return
	 */
	public Docket buildDocket(String apiGroupName) {
		return new Docket(DocumentationType.SWAGGER_2)
				.groupName(apiGroupName)
				//.apiInfo(buildBaseProductApiInfo(title, description, version))
				.useDefaultResponseMessages(false)
				.forCodeGeneration(false);
	}
	
	/**
	 * 根据分组key对API进行注册
	 * @param docket
	 * @param apiGroupKey
	 * @return
	 */
	public ApiSelectorBuilder buildApiForGroupKey(Docket docket, String apiGroupKey) {
		return docket.select()
				.apis(getPredicateWithGroup(apiGroupKey))
				.paths(PathSelectors.any());
	}
	
	/**
	 * 根据基础包名对API进行注册
	 * @param docket
	 * @param basePackage
	 * @return
	 */
	public ApiSelectorBuilder buildApiForPackage(Docket docket, String basePackage) {
		return docket.select()
				.apis(RequestHandlerSelectors.basePackage(basePackage))
				.paths(PathSelectors.any());
	}
	
	/**
	 * 构建API安全认证
	 * @param builder
	 * @return
	 */
	public Docket buildApiSecurityAuth(ApiSelectorBuilder builder) {
		return builder.build().securityContexts(Lists.newArrayList(buildSecurityContext()))
				.securitySchemes(Lists.newArrayList(apiSecurityKey()));
	}
	
	private ApiKey apiSecurityKey() {
		return new ApiKey("BearerToken", "Authorization", "header");
	}

	private SecurityContext buildSecurityContext() {
		return SecurityContext.builder()
				.securityReferences(defaultAuth())
				.forPaths(PathSelectors.regex("/.*"))
				.build();
	}

	/**
	 * 默认的认证方式
	 * @return
	 */
	private List<SecurityReference> defaultAuth() {
		AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
		AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
		authorizationScopes[0] = authorizationScope;
		return Lists.newArrayList(new SecurityReference("BearerToken", authorizationScopes));
	}

	/**
	 * 通过接口分组过滤
	 * @param group
	 * @return
	 */
	protected Predicate<RequestHandler> getPredicateWithGroup(String group) {
		return new Predicate<RequestHandler>() {
			@Override
			public boolean apply(RequestHandler input) {
				// 找到controller类上的ApiGroup注解
				Optional<ApiGroup> ApiGroup = input.findControllerAnnotation(ApiGroup.class);
				if(ApiGroup.isPresent() && Arrays.asList(ApiGroup.get().group()).contains(group)) {
					return true;
				}
				return false;
			}
		};
	}

	protected ApiInfo buildBaseProductApiInfo() {
		Contact contact = new Contact("liangyan", "www.Artfess.com", "liangyan@artfess.com");
		return buildApiInfo(title, description, version, "http://127.0.0.1:8080", contact);
	}

	@SuppressWarnings("rawtypes")
	protected ApiInfo buildApiInfo(String title, String description, String version, String url, Contact contact) {
		ApiInfo apiInfo = new ApiInfo(title, description, version, url, contact, "license", "license url",
				new ArrayList<VendorExtension>());
		return apiInfo;
	}

	/**
	 *
	 * 显示swagger-ui.html文档展示页，还必须注入swagger资源：
	 *
	 * @param registry
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
	}
}
