package runtime

import (
	"context"
	"testing"
	"time"
)

// MockLogger implements logging.Logger interface for testing
type MockLogger struct {
	messages []string
}

func (m *MockLogger) Info(format string, args ...interface{}) {
	m.messages = append(m.messages, "INFO")
}

func (m *MockLogger) Warn(format string, args ...interface{}) {
	m.messages = append(m.messages, "WARN")
}

func (m *MockLogger) Error(format string, args ...interface{}) {
	m.messages = append(m.messages, "ERROR")
}

func TestRuntimeTypes(t *testing.T) {
	// Test BinaryType enum
	agent := BinaryTypeAgent
	hap := BinaryTypeHAP

	if agent.String() != "agent" {
		t.Errorf("Expected 'agent', got %s", agent.String())
	}

	if hap.String() != "hap" {
		t.Errorf("Expected 'hap', got %s", hap.String())
	}

	// Test RuntimeError
	err := NewRuntimeError(ErrConfigInvalid, "test", BinaryTypeAgent, "test error", nil)
	if err.Code != ErrConfigInvalid {
		t.Errorf("Expected ErrConfigInvalid, got %v", err.Code)
	}

	if err.BinaryType != BinaryTypeAgent {
		t.Errorf("Expected BinaryTypeAgent, got %v", err.BinaryType)
	}

	if err.Error() != "test error" {
		t.Errorf("Expected 'test error', got %s", err.Error())
	}
}

func TestRuntimeInterface(t *testing.T) {
	// Test that we can create a runtime instance
	logger := &MockLogger{}
	runtime := NewRuntime(logger)

	if runtime == nil {
		t.Fatal("Expected non-nil runtime")
	}

	// Test that the runtime implements the Runtime interface
	var _ Runtime = runtime
}

func TestConfigValidator(t *testing.T) {
	// Test config validator creation
	validator := NewConfigValidator(BinaryTypeAgent)
	if validator == nil {
		t.Fatal("Expected non-nil validator")
	}

	if validator.binaryType != BinaryTypeAgent {
		t.Errorf("Expected BinaryTypeAgent, got %v", validator.binaryType)
	}
}

func TestTaskTracker(t *testing.T) {
	// Test task tracker creation and basic operations
	tracker := NewTaskTracker(5, "test-node", nil).(*TaskTracker)
	
	if tracker.GetMaxTasks() != 5 {
		t.Errorf("Expected max tasks 5, got %d", tracker.GetMaxTasks())
	}

	// Test task operations
	tracker.AddTask("task1")
	tasks := tracker.GetActiveTasks()
	if len(tasks) != 1 {
		t.Errorf("Expected 1 active task, got %d", len(tasks))
	}

	if !tracker.IsAvailable() {
		t.Error("Expected tracker to be available")
	}

	status := tracker.GetStatus()
	if status != "working" {
		t.Errorf("Expected status 'working', got %s", status)
	}

	// Remove task
	tracker.RemoveTask("task1")
	tasks = tracker.GetActiveTasks()
	if len(tasks) != 0 {
		t.Errorf("Expected 0 active tasks, got %d", len(tasks))
	}

	status = tracker.GetStatus()
	if status != "ready" {
		t.Errorf("Expected status 'ready', got %s", status)
	}
}

func TestCapabilityAnnouncer(t *testing.T) {
	// Test capability announcer creation
	announcer := NewCapabilityAnnouncer(nil, "test-node")
	if announcer == nil {
		t.Fatal("Expected non-nil announcer")
	}

	if announcer.nodeID != "test-node" {
		t.Errorf("Expected node ID 'test-node', got %s", announcer.nodeID)
	}
}

func TestStatusReporter(t *testing.T) {
	// Test status reporter creation
	reporter := NewStatusReporter(nil)
	if reporter == nil {
		t.Fatal("Expected non-nil reporter")
	}
}

// Test that our architecture properly separates concerns
func TestArchitectureSeparation(t *testing.T) {
	// Test that we can create runtime components independently
	logger := &MockLogger{}

	// Runtime
	runtime := NewRuntime(logger)
	if runtime == nil {
		t.Fatal("Failed to create runtime")
	}

	// Config validator
	agentValidator := NewConfigValidator(BinaryTypeAgent)
	hapValidator := NewConfigValidator(BinaryTypeHAP)

	if agentValidator.binaryType == hapValidator.binaryType {
		t.Error("Expected different binary types for validators")
	}

	// Task tracker
	tracker := NewTaskTracker(3, "test", nil)
	if tracker.GetMaxTasks() != 3 {
		t.Error("Task tracker not properly initialized")
	}

	// Capability announcer
	announcer := NewCapabilityAnnouncer(nil, "test")
	if announcer.nodeID != "test" {
		t.Error("Announcer not properly initialized")
	}

	t.Log("✅ All runtime components can be created independently")
}

// Benchmark basic operations
func BenchmarkTaskTrackerOperations(b *testing.B) {
	tracker := NewTaskTracker(100, "bench-node", nil).(*TaskTracker)

	b.Run("AddTask", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			taskID := "task-" + string(rune(i))
			tracker.AddTask(taskID)
		}
	})

	b.Run("GetActiveTasks", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			_ = tracker.GetActiveTasks()
		}
	})

	b.Run("GetStatus", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			_ = tracker.GetStatus()
		}
	})
}

func BenchmarkRuntimeErrorCreation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = NewRuntimeError(ErrConfigInvalid, "test", BinaryTypeAgent, "error", nil)
	}
}