package com.fjhx.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.fjhx.constants.FlowExplainConstant;
import com.fjhx.enums.ButtonNameEnum;
import com.fjhx.feign.IFlowClient;
import com.fjhx.params.ExampleResult;
import com.fjhx.params.JumpVo;
import org.springblade.core.tool.api.R;

public class FlowConstructor {

    private static IFlowClient flowClient;

    private synchronized static IFlowClient getFlowClient() {
        if (flowClient == null) {
            flowClient = SpringUtil.getBean(IFlowClient.class);
        }
        return flowClient;
    }

    private final ExampleAbstract exampleAbstract;

    /**
     * 初始化
     */
    public static FlowConstructor init(ExampleAbstract exampleAbstract) {
        return new FlowConstructor(exampleAbstract);
    }

    private FlowConstructor(ExampleAbstract exampleAbstract) {
        this.exampleAbstract = exampleAbstract;
    }

    /**
     * 业务异常回滚流程
     *
     * @param result 流程返回值
     */
    public static void rollBack(ExampleResult result) {
        getFlowClient().rollBack(result);
    }

    /**
     * 创建流程
     *
     * @param flowLinkNo 流程关联编号
     * @param title      标题
     * @param remarks    发起原因/备注
     * @return 流程实例对象
     */
    public ExampleResult create(Long flowLinkNo, String title, String remarks) {
        return create(flowLinkNo, title, remarks, null);
    }

    /**
     * 创建流程
     *
     * @param flowLinkNo 流程关联编号
     * @param title      标题
     * @param remarks    发起原因/备注
     * @param cacheData  缓存对象
     * @return 流程实例对象
     */
    public ExampleResult create(Long flowLinkNo, String title, String remarks, Object cacheData) {

        // 获取流程编码
        String code = getCode();

        // 缓存对象转字符串
        String cacheDataStr = getCacheDataStr(cacheData);

        // 赋值缓存
        exampleAbstract.setCacheData(cacheDataStr);
        String nodeCode = exampleAbstract.circulation();

        // 执行流程
        R<ExampleResult> exampleResultR = getFlowClient().create(flowLinkNo, code, nodeCode, title, remarks, cacheDataStr);
        ExampleResult result = Assert.result(exampleResultR);

        // 默认流程，直接执行结束方法
        if (ButtonNameEnum.END.getType().equals(result.getHandleType())) {
            try {
                exampleAbstract.end();
            } catch (Exception e) {
                rollBack(result);
                throw e;
            }
            return result;
        }

        JumpVo jumpVo = result.getJumpVo();
        jumpVo.setFlowLinkNo(flowLinkNo);
        jumpVo.setRemarks(remarks);
        jumpVo.setCacheDataStr(cacheDataStr);

        result = flowJump(jumpVo);
        result.setDeleteExample(true);

        return result;
    }

    public ExampleResult jump(JumpVo jumpVo) {
        return jump(jumpVo.getFlowLinkNo(), jumpVo.getButtonId(), jumpVo.getRemarks(), jumpVo.getCacheDataStr());
    }

    public ExampleResult jump(Long flowLinkNo, Long buttonId, String remarks) {
        return jump(flowLinkNo, buttonId, remarks, null);
    }

    /**
     * 流程跳转
     *
     * @param flowLinkNo 流程关联编号
     * @param buttonId   按钮id
     * @param remarks    审批意见
     * @param cacheData  缓存对象
     */
    public ExampleResult jump(Long flowLinkNo, Long buttonId, String remarks, Object cacheData) {

        // 缓存对象转字符串
        String cacheDataStr = getCacheDataStr(cacheData);

        // 赋值缓存
        exampleAbstract.setCacheData(cacheDataStr);
        String nodeCode = exampleAbstract.circulation();

        // 获取按钮
        JumpVo jumpVo = Assert.result(getFlowClient().getJumpVo(buttonId, nodeCode));
        jumpVo.setFlowLinkNo(flowLinkNo);
        jumpVo.setRemarks(remarks);
        jumpVo.setCacheDataStr(cacheDataStr);

        ExampleResult result = flowJump(jumpVo);
        result.setDeleteExample(false);
        return result;
    }

    /**
     * 流程跳转
     */
    private ExampleResult flowJump(JumpVo jumpVo) {

        R<ExampleResult> exampleResultR = getFlowClient().jump(jumpVo);
        ExampleResult result = Assert.result(exampleResultR);

        exampleAbstract.setCacheData(result.getCacheDataStr());
        try {
            switch (ButtonNameEnum.get(result.getHandleType())) {
                case END:
                    exampleAbstract.end();
                    break;

                case REJECT:
                    exampleAbstract.reject();
                    break;

                case FAIL:
                    exampleAbstract.fail();
                    break;

                case ADOPT:
                    exampleAbstract.adopt();
                    break;
            }
        } catch (Exception e) {
            rollBack(result);
            throw e;
        }
        return result;
    }

    /**
     * 缓存对象转字符串
     *
     * @param cacheData 缓存对象
     * @return 缓存字符串
     */
    private String getCacheDataStr(Object cacheData) {
        String cacheDataStr = "";
        if (ObjectUtil.isNotEmpty(cacheData)) {
            cacheDataStr = JSONObject.toJSONString(cacheData);
        }
        return cacheDataStr;
    }

    /**
     * 获取流程编码
     *
     * @return 流程编码
     */
    private String getCode() {
        String code = exampleAbstract.getCode();
        Assert.notEmpty(code, FlowExplainConstant.CODE_EMPTY);
        return code;
    }

    /**
     * 删除流程
     *
     * @param exampleInfoId 流程实例ID
     * @return
     */
    public boolean deleteLogic(Long exampleInfoId) {
        //根据流程实例ID删除流程（伪删除）
        Boolean flag = flowClient.deleteByExampleInfoId(exampleInfoId);
        if (flag) {
            flag = exampleAbstract.deleteLogic();
        }
        return flag;
    }
}
