package com.seer.teach.teacher.service.impl;

import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.teacher.LessonStateEnum;
import com.seer.teach.common.enums.teacher.LessonStateEvent;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.teacher.common.dto.LessonContextDTO;
import com.seer.teach.teacher.common.dto.TeachDTO;
import com.seer.teach.teacher.common.utils.CountdownExecutorUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.stereotype.Service;

import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

/**
 * 课程状态管理服务，基于 Spring StateMachine 实现。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LessonStateMachineService {

    private final StateMachineFactory<LessonStateEnum, LessonStateEvent> factory;

    private static final int COUNTDOWN_TIMEOUT = 5;

    /**
     * 用户状态机缓存
     */
    private final ConcurrentHashMap<Integer, StateMachine<LessonStateEnum, LessonStateEvent>> cache = new ConcurrentHashMap<>();

    /**
     * 获取或初始化用户状态机
     */
    private StateMachine<LessonStateEnum, LessonStateEvent> getStateMachine(Integer userId) {
        return cache.computeIfAbsent(userId, id -> {
            StateMachine<LessonStateEnum, LessonStateEvent> sm = factory.getStateMachine(String.valueOf(id));
            sm.start();
            log.info("状态机首次启动 userId={}", userId);
            return sm;
        });
    }

    /**
     * 获取或初始化用户课程上下文
     */
    private LessonContextDTO getLessonContext(Integer userId) {
        StateMachine<LessonStateEnum, LessonStateEvent> sm = getStateMachine(userId);
        return sm.getExtendedState().get("ctx", LessonContextDTO.class) != null
                ? sm.getExtendedState().get("ctx", LessonContextDTO.class)
                : initializeContext(sm);
    }

    /**
     * 初始化上下文
     */
    private LessonContextDTO initializeContext(StateMachine<LessonStateEnum, LessonStateEvent> sm) {
        LessonContextDTO ctx = new LessonContextDTO();
        ctx.setState(sm.getState().getId());
        sm.getExtendedState().getVariables().put("ctx", ctx);
        return ctx;
    }

    /**
     * 保存上下文
     */
    private void saveContext(Integer userId, LessonContextDTO ctx) {
        StateMachine<LessonStateEnum, LessonStateEvent> sm = getStateMachine(userId);
        sm.getExtendedState().getVariables().put("ctx", ctx);
        log.debug("LessonContextDTO 已保存 userId={}, state={}", userId, ctx.getState());
    }

    /**
     * 更新上下文并保存
     */
    private LessonContextDTO updateContext(Integer userId, Consumer<LessonContextDTO> updater) {
        LessonContextDTO ctx = getLessonContext(userId);
        updater.accept(ctx);
        saveContext(userId, ctx);
        return ctx;
    }

    /**
     * 统一发送状态事件并更新上下文
     */
    public LessonStateEnum sendEvent(Integer userId, LessonStateEvent event) {
        StateMachine<LessonStateEnum, LessonStateEvent> sm = getStateMachine(userId);
        LessonContextDTO ctx = getLessonContext(userId);
        try {
            if (!sm.sendEvent(event)) {
                log.warn("事件未被接受 userId={}, event={}", userId, event);
                return ctx.getState();
            }
            ctx.setState(sm.getState().getId());
            saveContext(userId, ctx);
            log.info("事件发送成功 userId={}, event={}, newState={}", userId, event, ctx.getState());
            return ctx.getState();
        } catch (Exception e) {
            log.error("事件发送失败 userId={}, event={}", userId, event, e);
            throw new CommonException(ResultCodeEnum.STATUS_UPDATE_ERROR);
        }
    }

    private StateMachine<LessonStateEnum, LessonStateEvent> getMachine(Integer userId) {
        return getStateMachine(userId);
    }

    /**
     * 设置教学信息
     */
    public void putTeach(Integer userId, TeachDTO dto) {
        updateContext(userId, ctx -> ctx.setTeachDTO(dto));
        log.info("教学信息更新成功 userId={}", userId);
    }

    /**
     * 获取教学信息
     */
    public TeachDTO getTeach(Integer userId) {
        return getLessonContext(userId).getTeachDTO();
    }

    /**
     * 更新音频播放顺序及播放状态
     */
    public void updateAudioSort(Integer userId, Integer audioSort) {
        updateContext(userId, ctx -> {
            ctx.setAudioSort(audioSort);
            ctx.setPlayingAudio(true);
        });
        log.info("更新 audioSort 成功 userId={}, audioSort={}", userId, audioSort);
    }

    /**
     * 获取课程上下文
     */
    public LessonContextDTO getContext(Integer userId) {
        return getLessonContext(userId);
    }

    /**
     * 判断是否已有课程上下文
     */
    public boolean hasLessonContext(Integer userId) {
        StateMachine<LessonStateEnum, LessonStateEvent> sm = cache.get(userId);
        return sm != null && sm.getExtendedState().get("ctx", LessonContextDTO.class) != null;
    }
}
