package service

import (
	"testing"

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

func TestBuildProgressTracker_Start(t *testing.T) {
	streams := memory.NewStreamPublisher()
	tracker := NewBuildProgressTracker(streams)

	tracker.Start("task-1", "project-1")

	phase, percentage, ok := tracker.GetProgress("task-1")
	if !ok {
		t.Fatal("expected to find progress for task-1")
	}
	if phase != domain.BuildPhaseStarting {
		t.Errorf("got phase %q, want %q", phase, domain.BuildPhaseStarting)
	}
	if percentage < 0 || percentage > 100 {
		t.Errorf("got invalid percentage %f", percentage)
	}
}

func TestBuildProgressTracker_RecordToolUse(t *testing.T) {
	streams := memory.NewStreamPublisher()
	tracker := NewBuildProgressTracker(streams)

	tracker.Start("task-1", "project-1")

	// Simulate reading phase
	tracker.RecordToolUse("task-1", "Read")
	phase, _, _ := tracker.GetProgress("task-1")
	if phase != domain.BuildPhaseReading {
		t.Errorf("after Read tool, got phase %q, want %q", phase, domain.BuildPhaseReading)
	}

	// Simulate writing phase
	tracker.RecordToolUse("task-1", "Write")
	phase, _, _ = tracker.GetProgress("task-1")
	if phase != domain.BuildPhaseWriting {
		t.Errorf("after Write tool, got phase %q, want %q", phase, domain.BuildPhaseWriting)
	}

	// Simulate testing phase
	tracker.RecordToolUse("task-1", "Bash")
	phase, _, _ = tracker.GetProgress("task-1")
	if phase != domain.BuildPhaseTesting {
		t.Errorf("after Bash tool, got phase %q, want %q", phase, domain.BuildPhaseTesting)
	}
}

func TestBuildProgressTracker_Complete(t *testing.T) {
	streams := memory.NewStreamPublisher()
	tracker := NewBuildProgressTracker(streams)

	tracker.Start("task-1", "project-1")
	tracker.Complete("task-1", true)

	// After completion, task should be removed
	_, _, ok := tracker.GetProgress("task-1")
	if ok {
		t.Error("expected task to be removed after completion")
	}
}

func TestBuildProgressTracker_PercentageIncrease(t *testing.T) {
	streams := memory.NewStreamPublisher()
	tracker := NewBuildProgressTracker(streams)

	tracker.Start("task-1", "project-1")

	_, initialPercent, _ := tracker.GetProgress("task-1")

	// Record several tool uses
	for i := 0; i < 5; i++ {
		tracker.RecordToolUse("task-1", "Read")
	}

	_, newPercent, _ := tracker.GetProgress("task-1")
	if newPercent <= initialPercent {
		t.Errorf("expected percentage to increase from %f, got %f", initialPercent, newPercent)
	}
}

func TestBuildProgressTracker_NonexistentTask(t *testing.T) {
	streams := memory.NewStreamPublisher()
	tracker := NewBuildProgressTracker(streams)

	// These should not panic
	tracker.RecordToolUse("nonexistent", "Read")
	tracker.RecordOutput("nonexistent")
	tracker.Complete("nonexistent", true)

	_, _, ok := tracker.GetProgress("nonexistent")
	if ok {
		t.Error("expected not to find progress for nonexistent task")
	}
}

func TestBuildProgressTracker_EmitsEvents(t *testing.T) {
	streams := memory.NewStreamPublisher()
	tracker := NewBuildProgressTracker(streams)

	// Subscribe to events
	events, cleanup := streams.Subscribe("task-1")
	defer cleanup()

	// Start should emit a progress event
	tracker.Start("task-1", "project-1")

	select {
	case event := <-events:
		if event.Type != "build.progress" {
			t.Errorf("got event type %q, want build.progress", event.Type)
		}
		phase, ok := event.Data["phase"].(string)
		if !ok || phase != "starting" {
			t.Errorf("got phase %v, want 'starting'", event.Data["phase"])
		}
	default:
		t.Error("expected progress event to be published")
	}
}
