/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
 */
package com.crunii.micro.gateway.swagger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author 田平 create 2019年8月28日下午2:45:22
 */
@Primary
@Component
@ConditionalOnProperty(name = "swagger.enabled", havingValue = "true")
public class SwaggerProvider implements SwaggerResourcesProvider {
	@Autowired
	private RouteLocator routeLocator;

	@Autowired
	private DiscoveryLocatorProperties discoveryProps;

	/**
	 * <pre>
	 *     swagger2默认的url后缀
	 *     注意不要使用v3，v3版本会丢失前缀 /api/serviceId
	 * </pre>
	 *
	 */
	public static final String SWAGGER2URL = "/v2/api-docs";

	/**
	 * 要忽略的服务名
	 */
	public static final String FLOW_SERVER = "flow-server";

	/**
	 * 网关应用名称
	 */
	@Value("${spring.application.name}")
	private String self;

	@Override
	public List<SwaggerResource> get() {
		List<SwaggerResource> resources = new ArrayList<>();
		Set<String> routeHosts = new HashSet<>();
		//由于网关采用的是负载均衡的方式，因此我需要拿到所有应用的serviceId
		//获取所有可用的host：serviceId
		routeLocator.getRoutes().filter(route -> {
			String disPrefix = discoveryProps.getRouteIdPrefix();
			if (!StringUtils.hasText(disPrefix)) {
				disPrefix = ReactiveCompositeDiscoveryClient.class.getSimpleName() + "_";
			}
			return "lb".equals(route.getUri().getScheme())
					&& !self.equals(route.getUri().getHost())
					&& route.getId().startsWith(disPrefix);
		}).subscribe(route -> routeHosts.add(route.getUri().getHost()));

		routeHosts.remove(FLOW_SERVER);
		// note：记录已经添加过的server，存在同一个应用注册了多个服务在nacos上
		Set<String> dealt = new HashSet<>();
		routeHosts.stream().sorted().forEach(instance -> {
			// note：当网关调用这个接口时，会自动通过负载均衡寻找对应的主机
			String url = "/" + instance + SWAGGER2URL;
			if (!dealt.contains(url)) {
				dealt.add(url);
				SwaggerResource swaggerResource = new SwaggerResource();
				swaggerResource.setUrl(url);
				swaggerResource.setName(instance);
				swaggerResource.setSwaggerVersion(DocumentationType.SWAGGER_2.getVersion());
				resources.add(swaggerResource);
			}
		});
		return resources;
	}

}
