package com.brilliance.isc.automatic.engine.flow;

import com.brilliance.isc.automatic.engine.config.AutoRouterConfig;
import com.brilliance.isc.automatic.engine.constant.enums.AutoStaEnum;
import com.brilliance.isc.automatic.engine.exception.AutomaticException;
import com.brilliance.isc.automatic.engine.model.AutoRoute;
import com.brilliance.isc.automatic.engine.model.FinishFlow;
import com.brilliance.isc.bo.auto.AutoFlow;
import com.brilliance.isc.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.Exchange;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import static com.brilliance.isc.automatic.engine.constant.AutomaticConstants.*;

/**
 * 自动化业务流程服务，根据具体自动化类型定制化部分特殊需求
 */
@Slf4j
public abstract class AutoFlowService {
    private final AutoFlowHelper helper = SpringUtils.getBean(AutoFlowHelper.class);
    private final AutoRouterConfig config;
    private final String type;

    public AutoFlowService(AutoRouterConfig config, String type) {
        this.config = config;
        this.type = type;
    }

    /**
     * 选择具体的业务流程
     */
    @Transactional
    public String next(Exchange exchange) {
        //获取接下来处理的路由流程
        AutoFlow autoFlow = helper.getOrCreateAutoFlow(exchange, config, () -> autoFolwCondition(exchange));
        if (ObjectUtils.isEmpty(autoFlow)) {
            if (log.isInfoEnabled()) {
                log.info("{}自动化结束", type);
            }
            return "";
        }
        if (log.isInfoEnabled()) {
            log.info("=================准备执行自动化任务[{}]的[{}]步骤=================", autoFlow.getInr(), autoFlow.getAddress());
        }
        helper.updateAutoFlowSta(autoFlow, AutoStaEnum.RUNNING, exchange);
        return autoFlow.getAddress();
    }

    /**
     * 当前流程执行完后的补充处理，以及是否继续执行下一步自动化
     */
    @Transactional
    public String hasNext(Exchange exchange) {
        AutoFlow autoFlow = helper.getCurAutoFlow(exchange);
        if (ObjectUtils.isEmpty(autoFlow)) {
            //如果从通道中拿不到流程信息，更新状态为异常，退出自动化
            helper.updateAutoFlowSta(autoFlow, AutoStaEnum.ERROR, exchange);
            return "";
        }
        if (autoFlow instanceof FinishFlow) {
            //重复调已经结束的自动化任务，直接结束
            helper.updateAutoFlowSta(autoFlow, AutoStaEnum.FINISH, exchange);
            return "";
        }
        if (isError(exchange, autoFlow)) {
            //如果有流程异常，更新流程信息表状态为异常，退出自动化
            helper.updateAutoFlowSta(autoFlow, AutoStaEnum.ERROR, exchange);
            return "";
        }
        if (isPause(exchange, autoFlow)) {
            //如果有流程暂停，更新流程信息表状态为暂停，退出自动化
            helper.updateAutoFlowSta(autoFlow, AutoStaEnum.PAUSE, exchange);
            return "";
        }
        //计算下一步流程
        AutoRoute nextAutoRoute = helper.findNextAutoRoute(config, autoFlow.getStep());
        if (ObjectUtils.isEmpty(nextAutoRoute)) {
            //如果流程成功，并且没有下一步流程，更新状态为结束，退出自动化
            helper.updateAutoFlowSta(autoFlow, AutoStaEnum.FINISH, exchange);
            return "";
        } else {
            //如果流程成功，并且有下一步流程，更新AutoFlow的路由名，序号和地址。
            helper.updateAutoFlowSta(autoFlow, AutoStaEnum.RUNNING, exchange);
            nextAutoRoute.fillAutoFlow(autoFlow);
            helper.setCurAutoFlow(exchange, autoFlow);
            preHandle(exchange, autoFlow);
            if (log.isInfoEnabled()) {
                log.info("=================计算自动化任务[{}]的下一步骤是[{}]=================", autoFlow.getInr(), autoFlow.getAddress());
            }
            //继续下一步自动化
            return AUTOMATIC_START_POINT;
        }

    }

    /**
     * 调起下一步自动化流程前的预处理，默认为空
     */
    protected void preHandle(Exchange exchange, AutoFlow autoFlow) {
        //默认没做什么，子类可以自己实现
    }

    /**
     * 默认从Exchange的CONDITION属性中获取AutoFlow的查询条件
     */
    protected AutoFlow autoFolwCondition(Exchange exchange) {
        return exchange.getProperty(AUTO_PAR, AutoFlow.class);
    }

    /**
     * 是否暂停
     */
    private boolean isPause(Exchange exchange, AutoFlow autoFlow) {
        AutoStaEnum pause = exchange.getProperty(AUTO_PAUSE, AutoStaEnum.class);
        if (!ObjectUtils.isEmpty(pause) && AutoStaEnum.PAUSE.equals(pause)) {
            return true;
        }
        if (AutoStaEnum.PAUSE.getCode().equals(autoFlow.getSta())) {
            return true;
        }
        return false;
    }

    /**
     * 是否错误
     */
    private boolean isError(Exchange exchange, AutoFlow autoFlow) {
        Exception exp = exchange.getProperty(CAMEL_EXCEPTION_KEY, Exception.class);
        Exception busExp = exchange.getProperty(CURRENT_STEP_EXCEPTION, Exception.class);
        if (!ObjectUtils.isEmpty(exp)) {
            autoFlow.setLsterr(exp.getMessage());
            return true;
        }
        if (!ObjectUtils.isEmpty(busExp)) {
            if (busExp instanceof AutomaticException) {
                autoFlow.setLsterr(((AutomaticException) busExp).getMessage());
            } else {
                autoFlow.setLsterr(busExp.getMessage());
            }
            return true;
        }
        if (AutoStaEnum.ERROR.getCode().equals(autoFlow.getSta())) {
            return true;
        }
        return false;
    }
}
