package service

import (
	"context"
	"testing"

	"github.com/orchard9/rdev/internal/domain"
)

func newTestWorkService() (*WorkService, *mockWorkQueue) {
	q := newMockWorkQueue()
	svc := NewWorkService(q)
	return svc, q
}

func TestWorkService_EnqueueTask(t *testing.T) {
	t.Run("success", func(t *testing.T) {
		svc, q := newTestWorkService()

		result, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{
			ProjectID: "myapp",
			Type:      domain.WorkTaskTypeBuild,
			Priority:  1,
			Spec:      map[string]any{"branch": "main"},
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if result.TaskID == "" {
			t.Error("task ID should not be empty")
		}
		if result.StatusURL == "" {
			t.Error("status URL should not be empty")
		}
		if len(q.tasks) != 1 {
			t.Errorf("tasks in queue = %d, want 1", len(q.tasks))
		}
	})

	t.Run("default max retries", func(t *testing.T) {
		svc, q := newTestWorkService()

		_, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{
			ProjectID: "myapp",
			Type:      domain.WorkTaskTypeBuild,
		})
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		for _, task := range q.tasks {
			if task.MaxRetries != 3 {
				t.Errorf("max retries = %d, want 3 (default)", task.MaxRetries)
			}
		}
	})

	t.Run("missing project id", func(t *testing.T) {
		svc, _ := newTestWorkService()

		_, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{
			Type: domain.WorkTaskTypeBuild,
		})
		if err == nil {
			t.Error("expected error for missing project_id")
		}
	})

	t.Run("missing type", func(t *testing.T) {
		svc, _ := newTestWorkService()

		_, err := svc.EnqueueTask(context.Background(), EnqueueTaskRequest{
			ProjectID: "myapp",
		})
		if err == nil {
			t.Error("expected error for missing type")
		}
	})
}

func TestWorkService_DequeueTask(t *testing.T) {
	t.Run("success", func(t *testing.T) {
		svc, q := newTestWorkService()

		// Enqueue a task first
		q.tasks["task-1"] = &domain.WorkTask{
			ID:        "task-1",
			ProjectID: "myapp",
			Type:      domain.WorkTaskTypeBuild,
			Status:    domain.WorkTaskStatusPending,
		}

		task, err := svc.DequeueTask(context.Background(), "worker-1")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if task == nil {
			t.Fatal("expected a task, got nil")
		}
		if task.ID != "task-1" {
			t.Errorf("task ID = %q, want %q", task.ID, "task-1")
		}
		if task.Status != domain.WorkTaskStatusRunning {
			t.Errorf("task status = %q, want %q", task.Status, domain.WorkTaskStatusRunning)
		}
	})

	t.Run("empty queue", func(t *testing.T) {
		svc, _ := newTestWorkService()

		task, err := svc.DequeueTask(context.Background(), "worker-1")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if task != nil {
			t.Error("expected nil task for empty queue")
		}
	})

	t.Run("missing worker id", func(t *testing.T) {
		svc, _ := newTestWorkService()

		_, err := svc.DequeueTask(context.Background(), "")
		if err == nil {
			t.Error("expected error for missing worker_id")
		}
	})
}

func TestWorkService_CompleteTask(t *testing.T) {
	t.Run("success", func(t *testing.T) {
		svc, q := newTestWorkService()

		q.tasks["task-1"] = &domain.WorkTask{
			ID:        "task-1",
			ProjectID: "myapp",
			Type:      domain.WorkTaskTypeBuild,
			Status:    domain.WorkTaskStatusRunning,
		}

		result := &domain.WorkResult{Output: "ok"}
		err := svc.CompleteTask(context.Background(), "task-1", result)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		task := q.tasks["task-1"]
		if task.Status != domain.WorkTaskStatusCompleted {
			t.Errorf("status = %q, want %q", task.Status, domain.WorkTaskStatusCompleted)
		}
	})

	t.Run("task not found", func(t *testing.T) {
		svc, _ := newTestWorkService()

		err := svc.CompleteTask(context.Background(), "nonexistent", nil)
		if err == nil {
			t.Error("expected error for nonexistent task")
		}
	})
}

func TestWorkService_GetTask(t *testing.T) {
	t.Run("found", func(t *testing.T) {
		svc, q := newTestWorkService()

		q.tasks["task-1"] = &domain.WorkTask{
			ID:        "task-1",
			ProjectID: "myapp",
		}

		task, err := svc.GetTask(context.Background(), "task-1")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if task.ID != "task-1" {
			t.Errorf("task ID = %q, want %q", task.ID, "task-1")
		}
	})

	t.Run("not found", func(t *testing.T) {
		svc, _ := newTestWorkService()

		_, err := svc.GetTask(context.Background(), "missing")
		if err == nil {
			t.Error("expected error for missing task")
		}
	})
}

func TestWorkService_GetStats(t *testing.T) {
	svc, _ := newTestWorkService()

	stats, err := svc.GetStats(context.Background())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if stats == nil {
		t.Error("stats should not be nil")
	}
}

func TestWorkService_CancelTask(t *testing.T) {
	svc, q := newTestWorkService()

	q.tasks["task-1"] = &domain.WorkTask{
		ID:        "task-1",
		ProjectID: "myapp",
		Status:    domain.WorkTaskStatusPending,
	}

	err := svc.CancelTask(context.Background(), "task-1")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
