// Package state_machine 提供广告状态机的单元测试
package state_machine

import (
	"server/internal/consts"
	"testing"
)

// TestNewAdStateMachine 测试创建新的广告状态机
func TestNewAdStateMachine(t *testing.T) {
	sm := NewAdStateMachine()
	if sm == nil {
		t.Fatal("期望创建非空的状态机，但得到了nil")
	}
	if sm.transitions == nil {
		t.Error("期望transitions非空，但得到了nil")
	}
	if sm.terminalStates == nil {
		t.Error("期望terminalStates非空，但得到了nil")
	}
}

// TestAdStateMachine_CanTransition 测试状态转换验证功能
func TestAdStateMachine_CanTransition(t *testing.T) {
	sm := NewAdStateMachine()

	// 测试有效转换
	if !sm.CanTransition(consts.StateFetchSuccess, consts.StateDisplaySuccess) {
		t.Error("期望从拉取成功到显示成功的转换是有效的")
	}

	// 测试无效转换
	if sm.CanTransition(consts.StateFetchSuccess, consts.StateNotWatched) {
		t.Error("期望从拉取成功到未观看完成的转换是无效的")
	}

	// 测试从终止状态转换
	if sm.CanTransition(consts.StateFetchFailed, consts.StateDisplaySuccess) {
		t.Error("期望从拉取失败终止状态无法转换到其他状态")
	}
}

// TestAdStateMachine_IsTerminalState 测试终止状态检查功能
func TestAdStateMachine_IsTerminalState(t *testing.T) {
	sm := NewAdStateMachine()

	// 测试终止状态
	if !sm.IsTerminalState(consts.StateDisplayFailed) {
		t.Error("期望显示失败状态是终止状态")
	}

	// 测试非终止状态
	if sm.IsTerminalState(consts.StateFetchSuccess) {
		t.Error("期望拉取成功状态不是终止状态")
	}
}

// TestAdStateMachine_GetAvailableTransitions 测试获取可用转换状态功能
func TestAdStateMachine_GetAvailableTransitions(t *testing.T) {
	sm := NewAdStateMachine()

	// 测试有可用转换的状态
	transitions := sm.GetAvailableTransitions(consts.StateFetchSuccess)
	if len(transitions) == 0 {
		t.Error("期望拉取成功状态有可用的转换状态")
	}

	// 测试终止状态
	transitions = sm.GetAvailableTransitions(consts.StateDisplayFailed)
	if len(transitions) != 0 {
		t.Error("期望显示失败终止状态没有可用的转换状态")
	}

	// 测试不存在的状态
	transitions = sm.GetAvailableTransitions(999) // 不存在的状态
	if len(transitions) != 0 {
		t.Error("期望不存在的状态没有可用的转换状态")
	}
}

// TestAdStateMachine_StateTransitionFlow 测试状态流转路径
func TestAdStateMachine_StateTransitionFlow(t *testing.T) {
	sm := NewAdStateMachine()

	// 测试路径1：拉取失败是终止状态
	if !sm.IsTerminalState(consts.StateFetchFailed) {
		t.Error("期望拉取失败是终止状态")
	}

	// 测试路径2：拉取成功 -> 显示失败 -> 终止
	if !sm.CanTransition(consts.StateFetchSuccess, consts.StateDisplayFailed) {
		t.Error("期望从拉取成功到显示失败的转换是有效的")
	}
	if !sm.IsTerminalState(consts.StateDisplayFailed) {
		t.Error("期望显示失败是终止状态")
	}

	// 测试路径3：拉取成功 -> 显示成功 -> 未观看完成 -> 终止
	if !sm.CanTransition(consts.StateFetchSuccess, consts.StateDisplaySuccess) {
		t.Error("期望从拉取成功到显示成功的转换是有效的")
	}
	if !sm.CanTransition(consts.StateDisplaySuccess, consts.StateNotWatched) {
		t.Error("期望从显示成功到未观看完成的转换是有效的")
	}
	if !sm.IsTerminalState(consts.StateNotWatched) {
		t.Error("期望未观看完成是终止状态")
	}

	// 测试路径4：拉取成功 -> 显示成功 -> 观看完成 -> 未点击 -> 终止
	if !sm.CanTransition(consts.StateDisplaySuccess, consts.StateWatched) {
		t.Error("期望从显示成功到观看完成的转换是有效的")
	}
	if !sm.CanTransition(consts.StateWatched, consts.StateNotClicked) {
		t.Error("期望从观看完成到未点击的转换是有效的")
	}
	if !sm.IsTerminalState(consts.StateNotClicked) {
		t.Error("期望未点击是终止状态")
	}

	// 测试路径5：拉取成功 -> 显示成功 -> 观看完成 -> 已点击 -> 未下载 -> 已下载
	if !sm.CanTransition(consts.StateWatched, consts.StateClicked) {
		t.Error("期望从观看完成到已点击的转换是有效的")
	}
	if !sm.CanTransition(consts.StateClicked, consts.StateNotDownloaded) {
		t.Error("期望从已点击到未下载的转换是有效的")
	}
	if sm.IsTerminalState(consts.StateNotDownloaded) {
		t.Error("期望未下载不是终止状态")
	}
	if !sm.CanTransition(consts.StateNotDownloaded, consts.StateDownloaded) {
		t.Error("期望从未下载到已下载的转换是有效的")
	}

	// 测试路径6：拉取成功 -> 显示成功 -> 观看完成 -> 已点击 -> 已下载 -> 终止
	if !sm.CanTransition(consts.StateClicked, consts.StateDownloaded) {
		t.Error("期望从已点击到已下载的转换是有效的")
	}
	if !sm.IsTerminalState(consts.StateDownloaded) {
		t.Error("期望已下载是终止状态")
	}
}

// TestAdStateMachine_InvalidTransitions 测试无效的状态转换
func TestAdStateMachine_InvalidTransitions(t *testing.T) {
	sm := NewAdStateMachine()

	// 测试不允许的跳跃转换
	if sm.CanTransition(consts.StateFetchSuccess, consts.StateWatched) {
		t.Error("不应该允许从拉取成功直接转换到观看完成")
	}
	if sm.CanTransition(consts.StateDisplaySuccess, consts.StateClicked) {
		t.Error("不应该允许从显示成功直接转换到已点击")
	}
	if sm.CanTransition(consts.StateWatched, consts.StateDownloaded) {
		t.Error("不应该允许从观看完成直接转换到已下载")
	}

	// 测试反向转换
	if sm.CanTransition(consts.StateDisplaySuccess, consts.StateFetchSuccess) {
		t.Error("不应该允许从显示成功转换回拉取成功")
	}
	if sm.CanTransition(consts.StateWatched, consts.StateDisplaySuccess) {
		t.Error("不应该允许从观看完成转换回显示成功")
	}
	if sm.CanTransition(consts.StateClicked, consts.StateWatched) {
		t.Error("不应该允许从已点击转换回观看完成")
	}
	if sm.CanTransition(consts.StateDownloaded, consts.StateClicked) {
		t.Error("不应该允许从已下载转换回已点击")
	}
}

// TestAdStateMachine_TransitionFromNotDownloaded 测试从未下载状态的转换
func TestAdStateMachine_TransitionFromNotDownloaded(t *testing.T) {
	sm := NewAdStateMachine()

	// 测试从未下载到已下载的转换
	if !sm.CanTransition(consts.StateNotDownloaded, consts.StateDownloaded) {
		t.Error("期望从未下载到已下载的转换是有效的")
	}

	// 确认未下载状态的可用转换只有已下载
	transitions := sm.GetAvailableTransitions(consts.StateNotDownloaded)
	if len(transitions) != 1 {
		t.Errorf("期望未下载状态有1个可用转换，但得到了%d个", len(transitions))
	}
	if len(transitions) > 0 && transitions[0] != consts.StateDownloaded {
		t.Errorf("期望未下载状态的可用转换是已下载，但得到了%d", transitions[0])
	}
}
