package com.hz.pm.api.common.statemachine.util;

import com.hz.pm.api.common.model.constant.StateMachineConst;
import com.hz.pm.api.common.statemachine.builder.ProjectDeclareStateMachineBuilder;
import com.hz.pm.api.common.statemachine.event.ProjectStatusChangeEvent;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.model.entity.ProjectStatusChange;
import com.hz.pm.api.projectlib.model.enumeration.ProjectStatusEnum;
import com.hz.pm.api.projectlib.service.INdProjectStatusChangeService;
import com.hz.pm.api.projectlib.service.IProjectApplicationService;
import com.ningdatech.basic.exception.BizException;
import com.wflow.exception.BusinessException;
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 java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Objects;

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

    private static final String PROJECT_DECLARE = StateMachineConst.PROJECT_DECLARE;

    private static final String APPLICATION_DECLARE = StateMachineConst.APPLICATION_DECLARE;

    //==================================================================================================================

    private final ProjectDeclareStateMachineBuilder projectDeclareStateMachineBuilder;

    private final INdProjectStatusChangeService projectStatusChangeService;

    private final IProjectApplicationService projectApplicationService;

    //通过审核
    public void pass(Project project) {
        try {
            execute(project, getProjectStatusPassEvent(project.getStatus()));
        } catch (Exception e) {
            log.info("状态机 通过失败 :{}", e.getMessage());
            throw new BusinessException("状态机 通过失败: " + e);
        }
    }

    //拒绝
    public void reject(Project project) {
        try {
            execute(project, getProjectStatusRejectEvent(project.getStatus()));
        } catch (Exception e) {
            log.info("状态机 拒绝失败 :{}", e.getMessage());
            throw new BusinessException("状态机 拒绝失败: " + e);
        }
    }

    //撤回
    public void withDraw(Project project) {
        try {
            execute(project, getProjectStatusWithdrawEvent(project.getStatus()));
        } catch (Exception e) {
            log.info("状态机 撤回失败 :{}", e.getMessage());
            throw new BusinessException("状态机 撤回失败: " + e);
        }
    }

    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<ProjectStatusChangeEvent> message = MessageBuilder.withPayload(event)
                .setHeader(PROJECT_DECLARE, project)
                .setHeader(APPLICATION_DECLARE, projectApplicationService.getApplicationsByProject(project))
                .build();
        //初始化状态机
        StateMachinePersister<ProjectStatusEnum, ProjectStatusChangeEvent, Project> projectDeclareStateMachinePersister = projectDeclareStateMachineBuilder.getProjectPersister();
        projectDeclareStateMachinePersister.restore(stateMachine, project);
        stateMachine.sendEvent(message);
        projectStatusChange.setProjectId(project.getId());
        projectStatusChange.setAfterStatus(project.getStatus());
        projectStatusChange.setEvent(event.name());
        projectStatusChange.setCreateOn(LocalDateTime.now());
        projectStatusChange.setProjectCode(project.getProjectCode());
        // 插入项目状态变更表中
        projectStatusChangeService.save(projectStatusChange);
        log.info("调用状态机后的项目状态为：{}", project.getStatus());
    }

    /**
     * 判断项目申报金额是否大于1000万元
     *
     * @param project \
     * @return boolean
     * @since 2023/02/07 17:13
     */
    public static boolean judgeDeclareAmount(Project project, BigDecimal targetAmount) {
        int flag = project.getDeclareAmount().compareTo(targetAmount);
        return flag > 0 || flag == 0;
    }

    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;
    }

}
