package cn.novalon.gym.manage.groupcourse.handler;

import cn.novalon.gym.manage.groupcourse.domain.GroupCourse;
import cn.novalon.gym.manage.groupcourse.enums.CourseEvent;
import cn.novalon.gym.manage.groupcourse.enums.CourseStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * 团课状态机处理器
 * 
 * 管理团课的状态转换逻辑
 * 
 * @author 张翔
 * @date 2026-06-02
 */
@Slf4j
@Component
public class GroupCourseStateMachine {

    private final Map<CourseStatus, Map<CourseEvent, CourseStatus>> stateTransitionMap;

    public GroupCourseStateMachine() {
        this.stateTransitionMap = buildStateTransitionMap();
    }

    private Map<CourseStatus, Map<CourseEvent, CourseStatus>> buildStateTransitionMap() {
        Map<CourseStatus, Map<CourseEvent, CourseStatus>> map = new HashMap<>();

        // NORMAL 状态可以转换的事件
        Map<CourseEvent, CourseStatus> normalTransitions = new HashMap<>();
        normalTransitions.put(CourseEvent.CANCEL, CourseStatus.CANCELLED);
        normalTransitions.put(CourseEvent.END, CourseStatus.ENDED);
        normalTransitions.put(CourseEvent.START, CourseStatus.IN_PROGRESS);
        map.put(CourseStatus.NORMAL, normalTransitions);

        // IN_PROGRESS 状态可以转换的事件
        Map<CourseEvent, CourseStatus> inProgressTransitions = new HashMap<>();
        inProgressTransitions.put(CourseEvent.END, CourseStatus.ENDED);
        map.put(CourseStatus.IN_PROGRESS, inProgressTransitions);

        // CANCELLED 状态是终态，不允许任何转换

        // ENDED 状态是终态，不允许任何转换

        return map;
    }

    /**
     * 检查是否可以转换状态
     */
    public Mono<Boolean> canTransition(CourseStatus currentState, CourseEvent event) {
        return Mono.fromSupplier(() -> {
            Map<CourseEvent, CourseStatus> transitions = stateTransitionMap.get(currentState);
            if (transitions == null) {
                return false;
            }
            return transitions.containsKey(event);
        });
    }

    /**
     * 执行状态转换
     */
    public Mono<CourseStatus> transition(CourseStatus currentState, CourseEvent event) {
        return Mono.fromSupplier(() -> {
            Map<CourseEvent, CourseStatus> transitions = stateTransitionMap.get(currentState);
            if (transitions == null || !transitions.containsKey(event)) {
                log.error("Invalid state transition: currentState={}, event={}", currentState, event);
                throw new IllegalStateException(
                        String.format("不允许的状态转换: 当前状态=%s, 事件=%s", currentState, event));
            }
            CourseStatus newState = transitions.get(event);
            log.info("State transition: {} --({})--> {}", currentState, event, newState);
            return newState;
        });
    }

    /**
     * 验证状态转换是否允许
     */
    public Mono<Void> validateTransition(GroupCourse course, CourseEvent event) {
        Long statusValue = course.getStatus();
        CourseStatus currentState = CourseStatus.fromValue(statusValue != null ? statusValue : 0L);
        
        return canTransition(currentState, event)
                .flatMap(canTransition -> {
                    if (!canTransition) {
                        String errorMessage = buildErrorMessage(course.getId(), currentState, event);
                        return Mono.error(new IllegalStateException(errorMessage));
                    }
                    return Mono.empty();
                });
    }

    /**
     * 构建状态转换错误信息
     */
    private String buildErrorMessage(Long courseId, CourseStatus currentState, CourseEvent event) {
        String currentStateDesc = currentState.getDesc();
        String eventDesc = event.getDesc();
        
        String advice = "";
        switch (currentState) {
            case CANCELLED:
                advice = "（课程已取消，无法进行此操作）";
                break;
            case ENDED:
                advice = "（课程已结束，无法进行此操作）";
                break;
            case IN_PROGRESS:
                if (event == CourseEvent.CANCEL) {
                    advice = "（课程正在进行中，无法取消）";
                }
                break;
            default:
                break;
        }
        
        return String.format("团课ID=%d 不允许的状态转换: 当前状态=%s(%s), 操作=%s%s",
                courseId, currentState, currentStateDesc, eventDesc, advice);
    }

    /**
     * 执行状态转换并更新课程对象
     */
    public Mono<GroupCourse> applyTransition(GroupCourse course, CourseEvent event) {
        return validateTransition(course, event)
                .then(transition(CourseStatus.fromValue(course.getStatus()), event))
                .map(newStatus -> {
                    course.setStatus(newStatus.getValue());
                    return course;
                });
    }
}