package com.bird.gateway.web.pipe.rpc.dubbo;

import com.alibaba.fastjson.JSON;
import com.bird.gateway.common.GatewayConstant;
import com.bird.gateway.common.dto.convert.DubboHandle;
import com.bird.gateway.common.RouteDefinition;
import com.bird.gateway.common.enums.PipeEnum;
import com.bird.gateway.common.enums.ResultEnum;
import com.bird.gateway.web.pipe.AbstractPipe;
import com.bird.gateway.web.pipe.PipeChain;
import com.bird.gateway.web.utils.HystrixBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;
import rx.Subscription;

import java.util.Objects;

/**
 * @author liuxx
 * @date 2018/11/29
 */
@Slf4j
public class DubboPipe extends AbstractPipe {

    private final DubboProxyService dubboProxyService;

    public DubboPipe(DubboProxyService dubboProxyService) {
        this.dubboProxyService = dubboProxyService;
    }

    @Override
    protected Mono<Void> doExecute(ServerWebExchange exchange, PipeChain chain, RouteDefinition routeDefinition) {

        DubboHandle dubboHandle = JSON.parseObject(routeDefinition.getRpcJson(), DubboHandle.class);

        if (!checkData(dubboHandle)) {
            return chain.execute(exchange);
        }

        DubboCommand command = new DubboCommand(HystrixBuilder.build(dubboHandle), exchange, chain, dubboHandle, dubboProxyService);
        return Mono.create((MonoSink<Object> s) -> {
            Subscription sub = command.toObservable().subscribe(s::success,
                    s::error, s::success);
            s.onCancel(sub::unsubscribe);
            if (command.isCircuitBreakerOpen()) {
                log.error(dubboHandle.getGroupKey() + ":dubbo execute circuitBreaker is Open !");
            }
        }).doOnError(throwable -> {
            throwable.printStackTrace();
            exchange.getAttributes().put(GatewayConstant.RESPONSE_RESULT_TYPE, ResultEnum.ERROR.getName());
            chain.execute(exchange);
        }).then();
    }

    private boolean checkData(final DubboHandle dubboHandle) {
        if (Objects.isNull(dubboHandle)
                || StringUtils.isBlank(dubboHandle.getRegistry())
                || StringUtils.isBlank(dubboHandle.getAppName())
                || StringUtils.isBlank(dubboHandle.getInterfaceName())
                || StringUtils.isBlank(dubboHandle.getMethodName())) {
            log.error("dubbo handle require param not config!");
            return false;
        }

        if (StringUtils.isBlank(dubboHandle.getGroupKey())) {
            dubboHandle.setGroupKey(dubboHandle.getInterfaceName());
        }
        if (StringUtils.isBlank(dubboHandle.getCommandKey())) {
            dubboHandle.setCommandKey(dubboHandle.getMethodName());
        }
        return true;
    }

    @Override
    public String named() {
        return PipeEnum.DUBBO.getName();
    }
}