package com.friday.distributor.statemachine;

import com.friday.distributor.constant.Events.*;
import com.friday.distributor.constant.States.*;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.stereotype.Component;

import java.util.EnumSet;

/**
 * @Author YaoYao
 * @Date Created In 13:38 2023/2/27
 * @Description 状态机builder
 * @Modified By
 */
@Component
public class DistributorStateMachineBuilder {
    @Autowired
    private TaskEventListener taskEventListener;
    @Autowired
    private JobEventListener jobEventListener;

    private final static String DISTRIBUTOR_TASK_STATE_MACHINE_ID = "TaieDistributorTaskMachine";
    private final static String DISTRIBUTOR_JOB_STATE_MACHINE_ID = "TaieDistributorJobMachine";

    public StateMachine<TaskState, TaskEvent> buildTaskStateMachine(BeanFactory beanFactory) throws Exception{
        StateMachineBuilder.Builder<TaskState, TaskEvent> builder = StateMachineBuilder.builder();
        builder.configureConfiguration()
                .withConfiguration()
                .machineId(DISTRIBUTOR_TASK_STATE_MACHINE_ID)
                .listener(taskEventListener)
                .beanFactory(beanFactory);
        builder.configureStates()
                .withStates()
                .initial(TaskState.UNEXECUTED)
                .states(EnumSet.allOf(TaskState.class));
        builder.configureTransitions()
                .withExternal()
                .source(TaskState.EXECUTING).target(TaskState.EXECUTING).event(TaskEvent.UPDATE_TASK)
                .and()
                .withExternal()
                .source(TaskState.UNEXECUTED).target(TaskState.EXECUTING).event(TaskEvent.START_TASK)
                .and()
                .withExternal().source(TaskState.EXECUTING).target(TaskState.EXECUTED).event(TaskEvent.FINISH_TASK);
        return builder.build();
    }

    public StateMachine<JobState, JobEvent> buildJobStateMachine(BeanFactory beanFactory) throws Exception{
        StateMachineBuilder.Builder<JobState, JobEvent> builder = StateMachineBuilder.builder();
        builder.configureConfiguration()
                .withConfiguration()
                .machineId(DISTRIBUTOR_JOB_STATE_MACHINE_ID)
                .listener(jobEventListener)
                .beanFactory(beanFactory);
        builder.configureStates()
                .withStates()
                .initial(JobState.UNSTART)
                .states(EnumSet.allOf(JobState.class));
        builder.configureTransitions()
                .withExternal()
                .source(JobState.UNSTART).target(JobState.RUNNING).event(JobEvent.START_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING).target(JobState.RUNNING).event(JobEvent.RETRY_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING).target(JobState.RUNNING).event(JobEvent.UPDATE_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING).target(JobState.SUCCESS).event(JobEvent.COMPLETE_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING).target(JobState.FAIL).event(JobEvent.FAIL_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING).target(JobState.TERMINATE).event(JobEvent.TERMINATE_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING_TIMEOUT).target(JobState.SUCCESS).event(JobEvent.COMPLETE_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING_TIMEOUT).target(JobState.FAIL).event(JobEvent.FAIL_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING_TIMEOUT).target(JobState.TERMINATE).event(JobEvent.TERMINATE_JOB)
                .and()
                .withExternal()
                .source(JobState.UNSTART).target(JobState.TERMINATE).event(JobEvent.TERMINATE_JOB)
                .and()
                .withExternal()
                .source(JobState.UNSTART).target(JobState.START_TIMEOUT).event(JobEvent.START_TIMEOUT_JOB)
                .and()
                .withExternal()
                .source(JobState.RUNNING).target(JobState.RUNNING_TIMEOUT).event(JobEvent.RUNNING_TIMEOUT_JOB);
        return builder.build();
    }
}
