package ink.wgink.gateway.component;

import ink.wgink.gateway.dao.route.IRouteDao;
import ink.wgink.gateway.dao.route.request.IRequestHeaderDao;
import ink.wgink.gateway.dao.route.request.IRequestParameterDao;
import ink.wgink.gateway.dao.route.request.IResponseHeaderDao;
import ink.wgink.gateway.enums.FilterRequestResponseTypeEnum;
import ink.wgink.gateway.filter.local.CommonFiltersDefinition;
import ink.wgink.gateway.pojo.route.Route;
import ink.wgink.gateway.pojo.route.request.RequestHeader;
import ink.wgink.gateway.pojo.route.request.RequestParameter;
import ink.wgink.gateway.pojo.route.request.ResponseHeader;
import ink.wgink.gateway.util.UUIDUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: RouteDefinitionRepository
 * @Description: 路由定义
 * @Author: wanggeng
 * @Date: 2021/4/22 4:04 下午
 * @Version: 1.0
 */
@Component
public class MongoRouteDefinitionRepository implements RouteDefinitionRepository {

    private IRouteDao routeDao;
    private MongoTemplate mongoTemplate;

    public MongoRouteDefinitionRepository(IRouteDao routeDao, MongoTemplate mongoTemplate) {
        this.routeDao = routeDao;
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return this.routeDefinitionFlux();
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }

    /**
     * 路由定义
     *
     * @return
     */
    private Flux<RouteDefinition> routeDefinitionFlux() {
        return routeDao.findAll().flatMap(route -> {
            // 定义路由
            RouteDefinition routeDefinition = new RouteDefinition();
            routeDefinition.setId(UUIDUtil.getUUID());
            routeDefinition.setUri(UriComponentsBuilder.fromUriString(route.getUri()).build().toUri());
            routeDefinition.setPredicates(this.listPredicateDefinition(route));
            // 过滤器
            routeDefinition.setFilters(this.listFilterDefinition(route));
            return Flux.just(routeDefinition);
        });
    }

    /**
     * 路由断言列表
     *
     * @param route
     * @return
     */
    private List<PredicateDefinition> listPredicateDefinition(Route route) {
        // 定义断言
        List<PredicateDefinition> predicateDefinitions = new ArrayList<>();
        // 路由断言
        PredicateDefinition pathPredicateDefinition = new PredicateDefinition();
        Map<String, String> pathPredicateDefinitionMap = new HashMap<>(2);
        pathPredicateDefinitionMap.put(RoutePredicateFactory.PATTERN_KEY, route.getPath());
        pathPredicateDefinition.setName("Path");
        pathPredicateDefinition.setArgs(pathPredicateDefinitionMap);
        // 添加路由断言
        predicateDefinitions.add(pathPredicateDefinition);
        return predicateDefinitions;
    }

    /**
     * 过滤器列表
     *
     * @return
     */
    private List<FilterDefinition> listFilterDefinition(Route route) {
        CommonFiltersDefinition commonFiltersDefinition = new CommonFiltersDefinition();
        // 定义过滤器
        List<FilterDefinition> filterDefinitions = new ArrayList<>();
        // 设置路径过滤器
        if (!StringUtils.isBlank(route.getSetPath())) {
            filterDefinitions.add(commonFiltersDefinition.setPath(route));
        }
        requestHeaderFilter(filterDefinitions, commonFiltersDefinition, route);
        requestParameterFilter(filterDefinitions, commonFiltersDefinition, route);
        responseHeaderFilter(filterDefinitions, commonFiltersDefinition, route);
        return filterDefinitions;
    }

    /**
     * 请求头过滤器
     *
     * @param filterDefinitions
     * @param commonFiltersDefinition
     */
    private void requestHeaderFilter(List<FilterDefinition> filterDefinitions, CommonFiltersDefinition commonFiltersDefinition, Route route) {
        // 添加请求头参数过滤器
        List<RequestHeader> addRequestHeaderList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.ADD.getValue())), RequestHeader.class, IRequestHeaderDao.COLLECTION_NAME);
        if (!addRequestHeaderList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.addRequestHeader(addRequestHeaderList));
        }
        // 设置请求头参数过滤器
        List<RequestHeader> setRequestHeaderList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.SET.getValue())), RequestHeader.class, IRequestHeaderDao.COLLECTION_NAME);
        if (!setRequestHeaderList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.setRequestHeader(setRequestHeaderList));
        }
        // 删除请求头参数过滤器
        List<RequestHeader> removeRequestHeaderList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.REMOVE.getValue())), RequestHeader.class, IRequestHeaderDao.COLLECTION_NAME);
        if (!removeRequestHeaderList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.removeRequestHeader(removeRequestHeaderList));
        }
    }

    /**
     * 请求参数过滤器
     *
     * @param filterDefinitions
     * @param commonFiltersDefinition
     */
    private void requestParameterFilter(List<FilterDefinition> filterDefinitions, CommonFiltersDefinition commonFiltersDefinition, Route route) {
        // 添加请求参数过滤器
        List<RequestParameter> addRequestParameterList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.ADD.getValue())), RequestParameter.class, IRequestParameterDao.COLLECTION_NAME);
        if (!addRequestParameterList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.addRequestParameter(addRequestParameterList));
        }
        // 删除请求参数过滤器
        List<RequestParameter> removeRequestParameterList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.REMOVE.getValue())), RequestParameter.class, IRequestParameterDao.COLLECTION_NAME);
        if (!removeRequestParameterList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.removeRequestParameter(removeRequestParameterList));
        }
    }

    /**
     * 响应头过滤器
     *
     * @param filterDefinitions
     * @param commonFiltersDefinition
     */
    private void responseHeaderFilter(List<FilterDefinition> filterDefinitions, CommonFiltersDefinition commonFiltersDefinition, Route route) {
        // 添加请求头参数过滤器
        List<ResponseHeader> addResponseHeaderList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.ADD.getValue())), ResponseHeader.class, IResponseHeaderDao.COLLECTION_NAME);
        if (!addResponseHeaderList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.addResponseHeader(addResponseHeaderList));
        }
        // 设置请求头参数过滤器
        List<ResponseHeader> setResponseHeaderList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.SET.getValue())), ResponseHeader.class, IResponseHeaderDao.COLLECTION_NAME);
        if (!setResponseHeaderList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.setResponseHeader(setResponseHeaderList));
        }
        // 删除请求头参数过滤器
        List<ResponseHeader> removeResponseHeaderList = mongoTemplate.find(new Query().addCriteria(Criteria.where("routeId").is(route.getUuid()).and("type").is(FilterRequestResponseTypeEnum.REMOVE.getValue())), ResponseHeader.class, IResponseHeaderDao.COLLECTION_NAME);
        if (!removeResponseHeaderList.isEmpty()) {
            filterDefinitions.add(commonFiltersDefinition.removeResponseHeader(removeResponseHeaderList));
        }
    }

}
