package pause

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestRequestPause(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	signal := &PauseSignal{
		WorkflowID:  "wf-1",
		Reason:      "manual pause",
		RequestedAt: time.Now(),
	}

	err := ph.RequestPause(signal)
	assert.NoError(t, err)
	assert.True(t, ph.IsPaused("wf-1"))
}

func TestRequestResume(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	// First pause
	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	assert.True(t, ph.IsPaused("wf-1"))

	// Then resume
	err := ph.RequestResume(&ResumeSignal{WorkflowID: "wf-1", Reason: "resume", RequestedAt: time.Now()})
	assert.NoError(t, err)
	assert.False(t, ph.IsPaused("wf-1"))
}

func TestIsPaused(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	assert.False(t, ph.IsPaused("wf-1"))

	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	assert.True(t, ph.IsPaused("wf-1"))
}

func TestGetPauseState(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	state := ph.GetPauseState("wf-1")

	assert.NotNil(t, state)
	assert.Equal(t, "wf-1", state.WorkflowID)
	assert.True(t, state.IsPaused)
	assert.Equal(t, "pause", state.PauseReason)
}

func TestSaveSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	snapshot, err := ph.SaveSnapshot(
		"wf-1",
		"stage1",
		[]string{"T1.1"},
		[]string{"T1.2"},
		nil,
		"T1.2",
		"activity-1",
		nil,
		nil,
		nil,
	)

	assert.NoError(t, err)
	assert.NotNil(t, snapshot)
	assert.Equal(t, "wf-1", snapshot.WorkflowID)
}

func TestRestoreSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	// Save snapshot
	ph.SaveSnapshot("wf-1", "stage1", []string{"T1.1"}, []string{"T1.2"}, nil, "T1.2", "", nil, nil, nil)

	// Restore it
	snapshot, err := ph.RestoreSnapshot("wf-1")
	assert.NoError(t, err)
	assert.NotNil(t, snapshot)
	assert.Equal(t, "wf-1", snapshot.WorkflowID)
}

func TestResetPauseState(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	assert.True(t, ph.IsPaused("wf-1"))

	err := ph.ResetPauseState("wf-1")
	assert.NoError(t, err)
	assert.Nil(t, ph.GetPauseState("wf-1"))
}

func TestGetAllPauseStates(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	ph.RequestPause(&PauseSignal{WorkflowID: "wf-2", Reason: "pause", RequestedAt: time.Now()})
	ph.RequestPause(&PauseSignal{WorkflowID: "wf-3", Reason: "pause", RequestedAt: time.Now()})

	states := ph.GetAllPauseStates()
	assert.Equal(t, 3, len(states))
}

func TestGetPauseStats(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	ph.RequestPause(&PauseSignal{WorkflowID: "wf-2", Reason: "pause", RequestedAt: time.Now()})
	ph.RequestResume(&ResumeSignal{WorkflowID: "wf-1", Reason: "resume", RequestedAt: time.Now()})

	stats := ph.GetPauseStats()
	assert.Equal(t, 2, stats["total"])
	assert.Equal(t, 1, stats["paused"])
	assert.Equal(t, 1, stats["resumed"])
}

func TestPauseStateFields(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	pausedTime := time.Now()
	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "manual pause", RequestedAt: pausedTime})

	state := ph.GetPauseState("wf-1")
	assert.Equal(t, "wf-1", state.WorkflowID)
	assert.True(t, state.IsPaused)
	assert.Equal(t, "manual pause", state.PauseReason)
	assert.NotZero(t, state.PausedAt)
}

func TestResumedAt(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	ph.RequestResume(&ResumeSignal{WorkflowID: "wf-1", Reason: "resume", RequestedAt: time.Now()})

	state := ph.GetPauseState("wf-1")
	assert.NotNil(t, state.ResumedAt)
}

func TestResumeNotPausedError(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	// Try to resume without pausing first
	err := ph.RequestResume(&ResumeSignal{WorkflowID: "wf-1", Reason: "resume", RequestedAt: time.Now()})
	assert.Error(t, err)
}

func TestNilSignals(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	err := ph.RequestPause(nil)
	assert.Error(t, err)

	err = ph.RequestResume(nil)
	assert.Error(t, err)
}

func TestMultipleWorkflowsPause(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	for i := 1; i <= 5; i++ {
		wfID := fmt.Sprintf("wf-%d", i)
		ph.RequestPause(&PauseSignal{WorkflowID: wfID, Reason: "pause", RequestedAt: time.Now()})
	}

	states := ph.GetAllPauseStates()
	assert.Equal(t, 5, len(states))

	for _, state := range states {
		assert.True(t, state.IsPaused)
	}
}

func TestWaitForPauseOrResume(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	// Send pause signal in goroutine
	go func() {
		time.Sleep(100 * time.Millisecond)
		ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})
	}()

	// Wait for pause
	isPaused, err := ph.WaitForPauseOrResume("wf-1", 1*time.Second)
	assert.NoError(t, err)
	assert.True(t, isPaused)
}

func TestWaitTimeout(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	// Wait with timeout should fail
	_, err := ph.WaitForPauseOrResume("wf-1", 100*time.Millisecond)
	assert.Error(t, err)
}

func TestSnapshotWithPause(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)
	ph := NewPauseHandler(sm)

	// Save snapshot before pausing
	snapshot, err := ph.SaveSnapshot("wf-1", "stage1", []string{"T1.1"}, []string{"T1.2"}, nil, "T1.2", "", nil, nil, nil)
	assert.NoError(t, err)

	// Pause
	ph.RequestPause(&PauseSignal{WorkflowID: "wf-1", Reason: "pause", RequestedAt: time.Now()})

	// State should have snapshot
	state := ph.GetPauseState("wf-1")
	assert.NotNil(t, state)
	assert.NotNil(t, state.CurrentSnapshot)
	assert.Equal(t, snapshot.WorkflowID, state.CurrentSnapshot.WorkflowID)
}
