package state_machine

import (
	"context"
	"sync"

	"github.com/gogf/gf/v2/os/glog"

	"server/internal/consts"
	"server/utility/ecode"
)

// AdStateMachine 广告状态机
type AdStateMachine struct {
	mu sync.RWMutex // 读写锁，保证并发安全
	// 状态流转规则
	transitions map[consts.AdState][]consts.AdState
	// 终止状态
	terminalStates map[consts.AdState]bool
}

// NewAdStateMachine 创建新的广告状态机
func NewAdStateMachine() *AdStateMachine {
	sm := &AdStateMachine{
		transitions:    make(map[consts.AdState][]consts.AdState),
		terminalStates: make(map[consts.AdState]bool),
	}

	// 初始化状态流转规则
	sm.initTransitions()
	return sm
}

// initTransitions 初始化状态流转规则
func (sm *AdStateMachine) initTransitions() {
	// 定义状态流转规则
	sm.transitions = map[consts.AdState][]consts.AdState{
		consts.StateFetchSuccess:   {consts.StateDisplayFailed, consts.StateDisplaySuccess},
		consts.StateDisplaySuccess: {consts.StateNotWatched, consts.StateWatched},
		consts.StateWatched:        {consts.StateNotClicked, consts.StateClicked},
		consts.StateClicked:        {consts.StateNotDownloaded, consts.StateDownloaded},
		consts.StateNotDownloaded:  {consts.StateDownloaded},
	}

	// 定义终止状态
	sm.terminalStates = map[consts.AdState]bool{
		consts.StateFetchFailed:   true,
		consts.StateDisplayFailed: true,
		consts.StateNotWatched:    true,
		consts.StateNotClicked:    true,
		consts.StateDownloaded:    true,
	}
}

// CanTransition 检查是否可以转换到目标状态
func (sm *AdStateMachine) CanTransition(fromState, toState consts.AdState) bool {
	sm.mu.RLock()
	defer sm.mu.RUnlock()

	// 检查是否为终止状态
	if sm.terminalStates[fromState] {
		return false
	}

	// 检查允许的转换
	allowedStates, exists := sm.transitions[fromState]
	if !exists {
		return false
	}

	for _, allowed := range allowedStates {
		if allowed == toState {
			return true
		}
	}

	return false
}

// Transition 执行状态转换
func (sm *AdStateMachine) Transition(ctx context.Context, flowID string, userID int64, fromState, toState consts.AdState, reason string) error {
	sm.mu.Lock()
	defer sm.mu.Unlock()

	// 验证状态转换
	if !sm.CanTransition(fromState, toState) {
		glog.Warningf(ctx, "Invalid state transition: %s -> %s, FlowID: %s, UserID: %d, Reason: %s",
			consts.GetStateDescription(fromState), consts.GetStateDescription(toState), flowID, userID, reason)
		return ecode.Params.Sub("invalid_state_transition")
	}

	// 记录状态转换日志
	glog.Infof(ctx, "State transition: %s -> %s, FlowID: %s, UserID: %d, Reason: %s",
		consts.GetStateDescription(fromState), consts.GetStateDescription(toState), flowID, userID, reason)

	return nil
}

// IsTerminalState 检查是否为终止状态
func (sm *AdStateMachine) IsTerminalState(state consts.AdState) bool {
	sm.mu.RLock()
	defer sm.mu.RUnlock()
	return sm.terminalStates[state]
}

// GetAvailableTransitions 获取当前状态可用的转换
func (sm *AdStateMachine) GetAvailableTransitions(currentState consts.AdState) []consts.AdState {
	sm.mu.RLock()
	defer sm.mu.RUnlock()

	if transitions, exists := sm.transitions[currentState]; exists {
		return transitions
	}
	return []consts.AdState{}
}
