package pause

import (
	"fmt"
	"testing"
	"time"

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

func TestCreateSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	snapshot, err := sm.CreateSnapshot(
		"wf-1",
		"implement",
		[]string{"T1.1", "T1.2"},
		[]string{"T1.3", "T1.4"},
		[]string{},
		"T1.3",
		"activity-1",
		map[string]interface{}{"duration": 42.5},
		map[string]interface{}{"total_time": 300},
		map[string]interface{}{"timeout": 600},
	)

	assert.NoError(t, err)
	assert.NotNil(t, snapshot)
	assert.Equal(t, "wf-1", snapshot.WorkflowID)
	assert.Equal(t, "implement", snapshot.Stage)
	assert.Equal(t, 2, len(snapshot.CompletedTasks))
	assert.Equal(t, 2, len(snapshot.PendingTasks))
	assert.NotZero(t, snapshot.PausedAt)
}

func TestGetLatestSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	retrieved := sm.GetLatestSnapshot("wf-1")

	assert.NotNil(t, retrieved)
	assert.Equal(t, "wf-1", retrieved.WorkflowID)
}

func TestHasSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	assert.False(t, sm.HasSnapshot("wf-1"))

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	assert.True(t, sm.HasSnapshot("wf-1"))
}

func TestRestoreFromSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	_, _ = sm.CreateSnapshot("wf-1", "stage1", []string{"T1.1"}, []string{"T1.2"}, nil, "T1.2", "", nil, nil, nil)

	restored, err := sm.RestoreFromSnapshot("wf-1")
	assert.NoError(t, err)
	assert.NotNil(t, restored)
	assert.Equal(t, "wf-1", restored.WorkflowID)
}

func TestMarkResumed(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	err := sm.MarkResumed("wf-1")
	assert.NoError(t, err)

	snapshot := sm.GetLatestSnapshot("wf-1")
	assert.NotNil(t, snapshot.ResumedAt)
}

func TestDeleteSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	assert.True(t, sm.HasSnapshot("wf-1"))

	err := sm.DeleteSnapshot("wf-1")
	assert.NoError(t, err)
	assert.False(t, sm.HasSnapshot("wf-1"))
}

func TestGetAllSnapshots(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	sm.CreateSnapshot("wf-2", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	sm.CreateSnapshot("wf-3", "stage1", nil, nil, nil, "", "", nil, nil, nil)

	snapshots := sm.GetAllSnapshots()
	assert.Equal(t, 3, len(snapshots))
}

func TestGetLastSnapshot(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	time.Sleep(10 * time.Millisecond)
	sm.CreateSnapshot("wf-2", "stage2", nil, nil, nil, "", "", nil, nil, nil)

	lastSnapshot := sm.GetLastSnapshot()
	assert.Equal(t, "wf-2", lastSnapshot.WorkflowID)
	assert.Equal(t, "stage2", lastSnapshot.Stage)
}

func TestGetSnapshotStats(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	sm.CreateSnapshot("wf-2", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	sm.MarkResumed("wf-1")

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

func TestClearOldSnapshots(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)

	// Mark as old
	snapshot := sm.GetLatestSnapshot("wf-1")
	snapshot.PausedAt = time.Now().Add(-2 * time.Hour)

	cleared, err := sm.ClearOldSnapshots(1 * time.Hour)
	assert.NoError(t, err)
	assert.Equal(t, 1, cleared)
	assert.False(t, sm.HasSnapshot("wf-1"))
}

func TestSnapshotPersistence(t *testing.T) {
	tmpDir := t.TempDir()
	sm1 := NewSnapshotManager(tmpDir)

	sm1.CreateSnapshot("wf-1", "stage1", []string{"T1.1"}, []string{"T1.2"}, nil, "T1.2", "", nil, nil, nil)

	// Create new manager and load
	sm2 := NewSnapshotManager(tmpDir)
	err := sm2.Load()
	assert.NoError(t, err)

	snapshot := sm2.GetLatestSnapshot("wf-1")
	assert.NotNil(t, snapshot)
	assert.Equal(t, "wf-1", snapshot.WorkflowID)
	assert.Equal(t, "stage1", snapshot.Stage)
}

func TestSnapshotMetrics(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	metrics := map[string]interface{}{
		"duration": 42.5,
		"count":    10,
	}

	snapshot, err := sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", metrics, nil, nil)
	assert.NoError(t, err)
	assert.NotNil(t, snapshot.TaskMetrics["duration"])
	assert.Equal(t, 42.5, snapshot.TaskMetrics["duration"])
}

func TestSnapshotConfiguration(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	config := map[string]interface{}{
		"timeout": 600,
		"retries": 3,
	}

	snapshot, err := sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, config)
	assert.NoError(t, err)
	assert.Equal(t, 600, snapshot.Configuration["timeout"])
}

func TestLoadNoSnapshots(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	err := sm.Load()
	assert.NoError(t, err)
	assert.Equal(t, 0, len(sm.GetAllSnapshots()))
}

func TestMultipleWorkflows(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	for i := 1; i <= 5; i++ {
		wfID := fmt.Sprintf("wf-%d", i)
		sm.CreateSnapshot(wfID, "stage1", nil, nil, nil, "", "", nil, nil, nil)
	}

	snapshots := sm.GetAllSnapshots()
	assert.Equal(t, 5, len(snapshots))
}

func TestSnapshotTimestamps(t *testing.T) {
	tmpDir := t.TempDir()
	sm := NewSnapshotManager(tmpDir)

	before := time.Now()
	sm.CreateSnapshot("wf-1", "stage1", nil, nil, nil, "", "", nil, nil, nil)
	after := time.Now()

	snapshot := sm.GetLatestSnapshot("wf-1")
	assert.True(t, snapshot.Timestamp.After(before) || snapshot.Timestamp.Equal(before))
	assert.True(t, snapshot.Timestamp.Before(after) || snapshot.Timestamp.Equal(after))
}
