package com.seer.teach.teacher.stateMachine;

import com.seer.teach.common.enums.teacher.LessonStateEnum;
import com.seer.teach.common.enums.teacher.LessonStateEvent;
import com.seer.teach.teacher.stateMachine.action.CancelAudioCountdownAction;
import com.seer.teach.teacher.stateMachine.action.SafeAction;
import com.seer.teach.teacher.stateMachine.action.StartAudioCountdownAction;
import com.seer.teach.teacher.stateMachine.action.lecture.LectureFinishTimeOutAction;
import com.seer.teach.teacher.stateMachine.action.lecture.LectureUserAskAction;
import com.seer.teach.teacher.stateMachine.action.lectureStop.LectureStopFinishTimeOutAction;
import com.seer.teach.teacher.stateMachine.action.lectureStop.LectureStopUserAskAction;
import com.seer.teach.teacher.stateMachine.action.modelAsk.ModelAskFinishTimeOutAction;
import com.seer.teach.teacher.stateMachine.action.modelAsk.ModelAskUserAskStateAction;
import com.seer.teach.teacher.stateMachine.action.summary.SummaryFinishTimeOutAction;
import com.seer.teach.teacher.stateMachine.action.summary.SummaryUserAskAction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;

/**
 * 课程状态机配置类，用于定义课程中各个状态之间的转换逻辑。
 * 使用Spring StateMachine框架实现有限状态机管理课程流程。
 * 包含状态定义、事件驱动的状态转移以及相关动作处理。
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
@EnableStateMachineFactory
public class LessonStateMachineConfig extends StateMachineConfigurerAdapter<LessonStateEnum, LessonStateEvent> {

    /**
     * 讲课暂停阶段超时动作处理器
     */
    private final LectureStopFinishTimeOutAction lectureStopFinishTimeOutAction;

    /**
     * 模型提问阶段超时动作处理器
     */
    private final ModelAskFinishTimeOutAction modelAskFinishTimeOutAction;

    /**
     * 讲课阶段超时动作处理器
     */
    private final LectureFinishTimeOutAction lectureFinishTimeOutAction;

    /**
     * 模型提问阶段用户提问动作处理器
     */
    private final ModelAskUserAskStateAction modelAskUserAskStateAction;

    /**
     * 总结阶段超时动作处理器
     */
    private final SummaryFinishTimeOutAction summaryFinishTimeOutAction;

    /**
     * 课程状态机监听器实例
     * 用于监听和处理课程状态变化事件
     */
    private final LessonStateMachineListener lessonStateMachineListener;

    /**
     * 取消音频倒计时动作处理器
     * 用于处理取消音频播放倒计时的相关操作
     */
    private final CancelAudioCountdownAction cancelAudioCountdownAction;

    /**
     * 开始音频倒计时动作处理器
     * 用于处理启动音频播放倒计时的相关操作
     */
    private final StartAudioCountdownAction startAudioCountdownAction;

    /**
     * 讲课暂停阶段用户提问动作处理器
     */
    private final LectureStopUserAskAction lectureStopUserAskAction;

    /**
     * 讲课阶段用户提问动作处理器
     */
    private final LectureUserAskAction lectureUserAskStateHandler;

    /**
     * 总结阶段用户提问动作处理器
     */
    private final SummaryUserAskAction summaryUserAskAction;

    /**
     * 配置状态机的基本配置
     *
     * @param config 状态机配置构建器，用于配置LessonStateEnum状态和LessonStateEvent事件相关的状态机
     * @throws Exception 配置过程中可能抛出的异常
     */
    @Override
    public void configure(StateMachineConfigurationConfigurer<LessonStateEnum, LessonStateEvent> config)
            throws Exception {
        config
                .withConfiguration()
                .listener(lessonStateMachineListener);  // 注册监听器
    }

    /**
     * 配置状态机中的所有状态。
     *
     * @param states 状态构建器，用于注册各种状态节点
     * @throws Exception 配置过程中可能抛出异常
     */
    @Override
    public void configure(StateMachineStateConfigurer<LessonStateEnum, LessonStateEvent> states) throws Exception {
        states
                .withStates()
                .initial(LessonStateEnum.LECTURE)           // 初始状态为“讲课”
                .state(LessonStateEnum.LECTURE_STOP)       // “讲课暂停”状态
                .state(LessonStateEnum.MODEL_ASK)          // “模型提问”状态
                .state(LessonStateEnum.SUMMARY);           // “总结”状态
    }


    /**
     * 配置状态间的转换规则及触发条件。
     *
     * @param transitions 转换构建器，用于设置状态间如何通过事件进行切换
     * @throws Exception 配置过程中可能抛出异常
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<LessonStateEnum, LessonStateEvent> transitions) throws Exception {
        transitions
                /* 开始讲课 ： 讲课 -> 讲课 */
                .withInternal()
                .source(LessonStateEnum.LECTURE)
                .event(LessonStateEvent.START_LESSON)

                /* 用户提问 ： 讲课 -> 讲课暂停  handler 完成 */
                .and().withExternal()
                .source(LessonStateEnum.LECTURE).target(LessonStateEnum.LECTURE_STOP)
                .event(LessonStateEvent.USER_ASK)
                .action(new SafeAction<>(cancelAudioCountdownAction))
                .action(new SafeAction<>(lectureUserAskStateHandler))

                /* 音频播放完成 ： 讲课 -> 讲课 ：延时5秒触发倒计时结束 */
                .and().withInternal()
                .source(LessonStateEnum.LECTURE)
                .event(LessonStateEvent.AUDIO_FINISH)
                .action(new SafeAction<>(startAudioCountdownAction))

                /* 倒计时结束 ： 讲课 -> 模型提问  handler 完成 */
                .and().withExternal()
                .source(LessonStateEnum.LECTURE).target(LessonStateEnum.MODEL_ASK)
                .event(LessonStateEvent.AUDIO_FINISH_TIMEOUT)
                .action(new SafeAction<>(lectureFinishTimeOutAction))

                /* 用户提问 ： 讲课暂停 -> 讲课暂停 handler 完成 */
                .and().withExternal()
                .source(LessonStateEnum.LECTURE_STOP).target(LessonStateEnum.LECTURE_STOP)
                .event(LessonStateEvent.USER_ASK)
                .action(new SafeAction<>(cancelAudioCountdownAction))
                .action(new SafeAction<>(lectureStopUserAskAction))

                /* 音频播放完成 : 讲课暂停 -> 讲课暂停 ： 延时5秒触发倒计时结束 */
                .and().withInternal()
                .source(LessonStateEnum.LECTURE_STOP)
                .event(LessonStateEvent.AUDIO_FINISH)
                .action(new SafeAction<>(startAudioCountdownAction))

                /* 倒计时结束 ： 讲课暂停 -> 讲课 handler 完成 */
                .and().withExternal()
                .source(LessonStateEnum.LECTURE_STOP).target(LessonStateEnum.LECTURE)
                .event(LessonStateEvent.AUDIO_FINISH_TIMEOUT)
                .action(new SafeAction<>(lectureStopFinishTimeOutAction))

                /* 用户提问： 模型提问 -> 模型提问 */
                .and().withExternal()
                .source(LessonStateEnum.MODEL_ASK).target(LessonStateEnum.MODEL_ASK)
                .event(LessonStateEvent.USER_ASK)
                .action(new SafeAction<>(cancelAudioCountdownAction))
                .action(new SafeAction<>(modelAskUserAskStateAction))

                /* 音频播放完成: 模型提问 -> 模型提问 ：延时5秒触发倒计时结束 */
                .and().withInternal()
                .source(LessonStateEnum.MODEL_ASK)
                .event(LessonStateEvent.AUDIO_FINISH)
                .action(new SafeAction<>(startAudioCountdownAction))

                /* 倒计时结束: 模型提问 -> 小结 */
                .and().withExternal()
                .source(LessonStateEnum.MODEL_ASK).target(LessonStateEnum.SUMMARY)
                .event(LessonStateEvent.AUDIO_FINISH_TIMEOUT)
                .action(new SafeAction<>(modelAskFinishTimeOutAction))

                /* 用户提问： 总结 -> 总结 */
                .and().withExternal()
                .source(LessonStateEnum.SUMMARY).target(LessonStateEnum.SUMMARY)
                .event(LessonStateEvent.USER_ASK)
                .action(new SafeAction<>(cancelAudioCountdownAction))
                .action(summaryUserAskAction)

                /* 音频播放完成: 总结 -> 总结 ： 延时5秒触发倒计时结束 */
                .and().withInternal()
                .source(LessonStateEnum.SUMMARY)
                .event(LessonStateEvent.AUDIO_FINISH)
                .action(new SafeAction<>(startAudioCountdownAction))

                /* 音频倒计时结束: 总结 -> 上课 ： 音频播放完成 */
                .and().withExternal()
                .source(LessonStateEnum.SUMMARY).target(LessonStateEnum.LECTURE)
                .event(LessonStateEvent.AUDIO_FINISH_TIMEOUT)
                .action(new SafeAction<>(summaryFinishTimeOutAction));
    }
}
