package ink.wgink.gateway.handler.route;

import ink.wgink.gateway.dao.route.IRouteDao;
import ink.wgink.gateway.handler.BaseHandler;
import ink.wgink.gateway.pojo.result.SuccessResult;
import ink.wgink.gateway.pojo.route.Route;
import ink.wgink.gateway.util.UUIDUtil;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.annotation.Order;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: RouteHandler
 * @Description: 路由
 * @Author: WangGeng
 * @Date: 2021/4/19 21:40
 * @Version: 1.0
 **/
@Service
public class RouteHandler extends BaseHandler implements ApplicationEventPublisherAware {

    private IRouteDao routeDao;
    private ApplicationEventPublisher applicationEventPublisher;

    public RouteHandler(IRouteDao routeDao) {
        this.routeDao = routeDao;
    }

    /**
     * 新增
     *
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> save(ServerRequest serverRequest) {
        Mono<Route> routeMono = serverRequest.bodyToMono(Route.class);
        return routeMono.flatMap(route -> {
            setSave(route);
            return routeDao.save(route);
        }).then(ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Flux.just(new SuccessResult()), SuccessResult.class));
    }

    /**
     * 删除
     *
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> delete(ServerRequest serverRequest) {
        String ids = serverRequest.pathVariable("ids");
        List<String> idList = Arrays.asList(ids.split(","));
        return routeDao.findAllById(idList).flatMap(
                route -> routeDao.delete(route)
        ).then(ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Mono.just(new SuccessResult()), SuccessResult.class));
    }

    /**
     * 修改
     *
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> update(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        Mono<Route> routeMono = serverRequest.bodyToMono(Route.class);
        return routeDao.findById(id).flatMap(
                route -> routeMono.flatMap(r -> {
                    route.setTitle(r.getTitle());
                    route.setSummary(r.getSummary());
                    route.setPath(r.getPath());
                    route.setUri(r.getUri());
                    setUpdate(route);
                    return routeDao.save(route);
                }).then(ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Flux.just(new SuccessResult()), SuccessResult.class))
        ).switchIfEmpty(ServerResponse.notFound().build());
    }

    /**
     * 列表
     *
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> list(ServerRequest serverRequest) {
        Optional<String> keywords = serverRequest.queryParam("keywords");

        Route route = new Route();
        Example example = Example.of(route);
        if (keywords.isPresent()) {
            route.setTitle(keywords.get());
            route.setSummary(keywords.get());

            ExampleMatcher exampleMatcher = ExampleMatcher.matchingAny()
                    .withMatcher("title", ExampleMatcher.GenericPropertyMatcher::contains)
                    .withMatcher("summary", ExampleMatcher.GenericPropertyMatcher::contains)
                    .withIgnoreCase("id");
            example = Example.of(route, exampleMatcher);
        }
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(routeDao.findAll(example), Route.class);
    }

    /**
     * 列表
     *
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> get(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        return routeDao.findById(id).flatMap(
                route -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Mono.just(route), Route.class)
        ).switchIfEmpty(ServerResponse.notFound().build());
    }

    /**
     * 通知刷新路由
     *
     * @param serverRequest
     * @return
     */
    public Mono<ServerResponse> refresh(ServerRequest serverRequest) {
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(new SuccessResult()), SuccessResult.class);
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
