package utils

import "testing"

func TestLinearStateMachine_RunPause(t *testing.T) {
	callCount := 0
	lsm := NewLinearStateMachine(
		func() LSMAction {
			callCount++
			return LSMActionPause
		},
	)
	cancelled, done := lsm.Run()
	if cancelled {
		t.Error("unexpected cancelled=true")
	}
	if done {
		t.Error("unexpected done=true")
	}
	if callCount != 1 {
		t.Errorf("callCount = %d, want 1", callCount)
	}
}

func TestLinearStateMachine_RunNext(t *testing.T) {
	callOrder := []int{}
	lsm := NewLinearStateMachine(
		func() LSMAction { callOrder = append(callOrder, 1); return LSMActionNext },
		func() LSMAction { callOrder = append(callOrder, 2); return LSMActionNext },
		func() LSMAction { callOrder = append(callOrder, 3); return LSMActionNext },
	)
	cancelled, done := lsm.Run()
	if cancelled {
		t.Error("unexpected cancelled=true")
	}
	if !done {
		t.Error("unexpected done=false")
	}
	if len(callOrder) != 3 {
		t.Fatalf("callOrder len = %d, want 3", len(callOrder))
	}
	for i, v := range []int{1, 2, 3} {
		if callOrder[i] != v {
			t.Errorf("callOrder[%d] = %d, want %d", i, callOrder[i], v)
		}
	}
}

func TestLinearStateMachine_RunReset(t *testing.T) {
	callCount := 0
	lsm := NewLinearStateMachine(
		func() LSMAction {
			callCount++
			if callCount == 1 {
				return LSMActionReset
			}
			return LSMActionNext
		},
		func() LSMAction { callCount++; return LSMActionNext },
	)
	cancelled, done := lsm.Run()
	if cancelled {
		t.Error("unexpected cancelled=true")
	}
	if !done {
		t.Error("unexpected done=false")
	}
	if callCount != 3 {
		t.Errorf("callCount = %d, want 3 (step0 reset, step0 next, step1 next)", callCount)
	}
}

func TestLinearStateMachine_RunCancel(t *testing.T) {
	callCount := 0
	lsm := NewLinearStateMachine(
		func() LSMAction { callCount++; return LSMActionNext },
		func() LSMAction { callCount++; return LSMActionCancel },
		func() LSMAction { callCount++; return LSMActionNext },
	)
	cancelled, done := lsm.Run()
	if !cancelled {
		t.Error("unexpected cancelled=false")
	}
	if !done {
		t.Error("unexpected done=false")
	}
	if callCount != 2 {
		t.Errorf("callCount = %d, want 2 (third step should not execute)", callCount)
	}
}

func TestLinearStateMachine_RunMixed(t *testing.T) {
	pauseCount := 0
	lsm := NewLinearStateMachine(
		func() LSMAction { return LSMActionNext },
		func() LSMAction {
			pauseCount++
			if pauseCount == 1 {
				return LSMActionPause
			}
			return LSMActionNext
		},
		func() LSMAction { return LSMActionNext },
		func() LSMAction { return LSMActionNext },
	)
	cancelled, done := lsm.Run()
	if cancelled {
		t.Error("unexpected cancelled=true")
	}
	if done {
		t.Error("unexpected done=true on first run")
	}
	cancelled, done = lsm.Run()
	if cancelled {
		t.Error("unexpected cancelled=true on second run")
	}
	if !done {
		t.Error("unexpected done=false on second run")
	}
}

func TestLinearStateMachine_RunEmpty(t *testing.T) {
	lsm := NewLinearStateMachine()
	cancelled, done := lsm.Run()
	if cancelled {
		t.Error("unexpected cancelled=true")
	}
	if !done {
		t.Error("unexpected done=false for empty LSM")
	}
}

func TestLinearStateMachine_AppendSteps(t *testing.T) {
	lsm := NewLinearStateMachine(
		func() LSMAction { return LSMActionNext },
	)
	lsm.Run()
	lsm.AppendSteps(
		func() LSMAction { return LSMActionNext },
	)
	_, done := lsm.Run()
	if !done {
		t.Error("unexpected done=false after AppendSteps")
	}
}

func TestLinearStateMachine_Reset(t *testing.T) {
	callCount := 0
	lsm := NewLinearStateMachine(
		func() LSMAction { callCount++; return LSMActionCancel },
	)
	lsm.Run()
	if !lsm.cancelled {
		t.Error("expected cancelled=true after cancel")
	}
	lsm.Reset()
	if lsm.cancelled {
		t.Error("expected cancelled=false after Reset")
	}
	if lsm.index != 0 {
		t.Errorf("expected index=0 after Reset, got %d", lsm.index)
	}
	_, done := lsm.Run()
	if !done {
		t.Error("expected done=true, step executed again after Reset")
	}
	if callCount != 2 {
		t.Errorf("callCount = %d, want 2 (first run + reset run)", callCount)
	}
}

func TestLSMActionConstants(t *testing.T) {
	if LSMActionPause != 0 {
		t.Errorf("LSMActionPause = %d, want 0", LSMActionPause)
	}
	if LSMActionNext != 1 {
		t.Errorf("LSMActionNext = %d, want 1", LSMActionNext)
	}
	if LSMActionReset != 2 {
		t.Errorf("LSMActionReset = %d, want 2", LSMActionReset)
	}
	if LSMActionCancel != 3 {
		t.Errorf("LSMActionCancel = %d, want 3", LSMActionCancel)
	}
}
