package queue

import (
	"testing"
	"time"

	"github.com/alicebob/miniredis/v2"
	"github.com/stretchr/testify/require"

	"github.com/jfraeys/fetch_ml/internal/queue"
)

const testUser = "testuser"

func TestTask_UserFields(t *testing.T) {
	t.Parallel()
	task := &queue.Task{
		UserID:    "testuser",
		Username:  "testuser",
		CreatedBy: "testuser",
	}

	if task.UserID != "testuser" {
		t.Errorf("Expected UserID to be 'testuser', got '%s'", task.UserID)
	}

	if task.Username != testUser {
		t.Errorf("Expected Username to be 'testuser', got '%s'", task.Username)
	}

	if task.CreatedBy != testUser {
		t.Errorf("Expected CreatedBy to be 'testuser', got '%s'", task.CreatedBy)
	}
}

func TestTaskQueue_UserFiltering(t *testing.T) {
	// Setup test Redis configuration
	s, err := miniredis.Run()
	if err != nil {
		t.Skip("Redis not available for integration testing")
	}
	t.Cleanup(s.Close)

	queueCfg := queue.Config{
		RedisAddr: s.Addr(),
		RedisDB:   15, // Use dedicated test DB
	}

	// Create task queue
	taskQueue, err := queue.NewTaskQueue(queueCfg)
	if err != nil {
		t.Skip("Redis not available for integration testing")
		return
	}
	t.Cleanup(func() {
		if err := taskQueue.Close(); err != nil {
			t.Logf("Warning: failed to close task queue: %v", err)
		}
	})

	// Clear test database
	s.FlushAll()

	// Create test tasks with different users
	tasks := []*queue.Task{
		{
			ID:        "task1",
			JobName:   "user1_job1",
			Status:    "queued",
			UserID:    "user1",
			CreatedBy: "user1",
			CreatedAt: time.Now(),
		},
		{
			ID:        "task2",
			JobName:   "user1_job2",
			Status:    "running",
			UserID:    "user1",
			CreatedBy: "user1",
			CreatedAt: time.Now(),
		},
		{
			ID:        "task3",
			JobName:   "user2_job1",
			Status:    "queued",
			UserID:    "user2",
			CreatedBy: "user2",
			CreatedAt: time.Now(),
		},
		{
			ID:        "task4",
			JobName:   "admin_job",
			Status:    "completed",
			UserID:    "admin",
			CreatedBy: "admin",
			CreatedAt: time.Now(),
		},
	}

	// Add tasks to queue
	for _, task := range tasks {
		require.NoError(t, taskQueue.AddTask(task))
	}

	// Test GetAllTasks
	allTasks, err := taskQueue.GetAllTasks()
	require.NoError(t, err)
	if len(allTasks) != len(tasks) {
		t.Errorf("Expected %d tasks, got %d", len(tasks), len(allTasks))
	}

	// Test user filtering logic
	filterTasksForUser := func(tasks []*queue.Task, userID string) []*queue.Task {
		var filtered []*queue.Task
		for _, task := range tasks {
			if task.UserID == userID || task.CreatedBy == userID {
				filtered = append(filtered, task)
			}
		}
		return filtered
	}

	// Test filtering for user1 (should get 2 tasks)
	user1Tasks := filterTasksForUser(allTasks, "user1")
	if len(user1Tasks) != 2 {
		t.Errorf("Expected 2 tasks for user1, got %d", len(user1Tasks))
	}

	// Test filtering for user2 (should get 1 task)
	user2Tasks := filterTasksForUser(allTasks, "user2")
	if len(user2Tasks) != 1 {
		t.Errorf("Expected 1 task for user2, got %d", len(user2Tasks))
	}

	// Test filtering for admin (should get 1 task)
	adminTasks := filterTasksForUser(allTasks, "admin")
	if len(adminTasks) != 1 {
		t.Errorf("Expected 1 task for admin, got %d", len(adminTasks))
	}

	// Test GetTaskByName
	task, err := taskQueue.GetTaskByName("user1_job1")
	if err != nil {
		t.Errorf("Failed to get task by name: %v", err)
	}
	if task == nil || task.UserID != "user1" {
		t.Error("Got wrong task or nil task")
	}

	// Test CancelTask
	require.NoError(t, taskQueue.CancelTask("task1"))

	// Verify task was cancelled
	cancelledTask, err := taskQueue.GetTask("task1")
	require.NoError(t, err)
	if cancelledTask.Status != "cancelled" {
		t.Errorf("Expected status 'cancelled', got '%s'", cancelledTask.Status)
	}
}
