package com.ningdatech.pmapi.common.statemachine.util;

import com.ningdatech.basic.exception.BizException;
import com.ningdatech.pmapi.common.constant.ProjectDeclareConst;
import com.ningdatech.pmapi.common.constant.StateMachineConst;
import com.ningdatech.pmapi.common.statemachine.builder.ProjectDeclareStateMachineBuilder;
import com.ningdatech.pmapi.common.statemachine.event.ProjectStatusChangeEvent;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectStatusChange;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.INdProjectStatusChangeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 状态机工具类
 *
 * @author CMM
 * @since 2023/02/07 22:49
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class StateMachineUtils {

    private static final String PROJECT_DECLARE = StateMachineConst.PROJECT_DECLARE;

    private final ProjectDeclareStateMachineBuilder projectDeclareStateMachineBuilder;

    private final INdProjectStatusChangeService projectStatusChangeService;

    @Resource(name = "projectDeclareStateMachinePersister")
    private StateMachinePersister projectDeclareStateMachinePersister;

    public void execute(Project project, ProjectStatusChangeEvent event) throws Exception {
        log.info("调用状态机前的项目状态为>>>>>>>>>>{}" + project.getStatus());
        // 将状态变更记录保存到项目状态变更表中
        ProjectStatusChange projectStatusChange = new ProjectStatusChange();
        projectStatusChange.setBeforeStatus(project.getStatus());
        //获取TO状态机
        StateMachine<ProjectStatusEnum, ProjectStatusChangeEvent> stateMachine = projectDeclareStateMachineBuilder.build();
        Message message = MessageBuilder.withPayload(event).setHeader(PROJECT_DECLARE, project).build();
        //初始化状态机
        projectDeclareStateMachinePersister.restore(stateMachine, project);
        stateMachine.sendEvent(message);
        projectStatusChange.setProjectId(project.getId());
        projectStatusChange.setAfterStatus(project.getStatus());
        projectStatusChange.setEvent(event.name());
        projectStatusChange.setCreateOn(LocalDateTime.now());
        // 插入项目状态变更表中
        projectStatusChangeService.save(projectStatusChange);
        log.info("调用状态机后的项目状态为>>>>>>>>>>{}" + project.getStatus());
    }

    /**
     * 判断项目申报金额是否大于1000万元
     *
     * @param project
     * @return boolean
     * @author CMM
     * @since 2023/02/07 17:13
     */
    public static boolean judgeDeclareAmount(Project project) {
        int flag = project.getDeclareAmount().compareTo(ProjectDeclareConst.Number.DECLARE_AMOUNT_JUDGEMENT);
        if (flag > 0 || flag == 0) {
            return true;
        }
        return false;
    }

    /**
     * 判断申报项目是否为市级项目
     *
     * @param project
     * @return boolean
     * @author CMM
     * @since 2023/02/07 17:05
     */
    public static boolean isCityProject(Project project) {
        String areaCode = project.getAreaCode();
        if (areaCode.equals(StateMachineConst.LI_SHUI_CITY_AREA_CODE)) {
            return true;
        }
        return false;
    }

    public ProjectStatusChangeEvent getProjectStatusPassEvent(Integer status) {
        ProjectStatusChangeEvent event = ProjectStatusChangeEvent.getPassValueByCode(status);
        if (Objects.isNull(event)) {
            throw new BizException("该状态下没有对应的通过操作！");
        }
        return event;
    }

    public ProjectStatusChangeEvent getProjectStatusRejectEvent(Integer status) {
        ProjectStatusChangeEvent event = ProjectStatusChangeEvent.getRejectValueByCode(status);
        if (Objects.isNull(event)) {
            throw new BizException("该状态下没有对应的驳回操作！");
        }
        return event;
    }

    public ProjectStatusChangeEvent getProjectStatusWithdrawEvent(Integer status) {
        ProjectStatusChangeEvent event = ProjectStatusChangeEvent.getWithdrawValueByCode(status);
        if (Objects.isNull(event)) {
            throw new BizException("该状态下没有对应的撤回操作！");
        }
        return event;
    }
}
