package routing

import (
	"testing"
)

func TestValidateValidWorkflowSpec(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test-workflow",
		Input: map[string]interface{}{
			"repo": "https://github.com/test/repo",
		},
		States: []State{
			{
				Name:     "Clone",
				Type:     StateTypeTask,
				Resource: "CloneRepoActivity",
				Parameters: map[string]interface{}{
					"repo": "${input.repo}",
				},
				Timeout: "5m",
				Next:    "Analyze",
			},
			{
				Name:     "Analyze",
				Type:     StateTypeTask,
				Resource: "AnalyzeCodeActivity",
				Parameters: map[string]interface{}{
					"path": "${Clone.output.path}",
				},
				Timeout: "10m",
				End:     true,
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if !result.Valid {
		t.Errorf("Spec should be valid. Errors: %v", result.Errors)
	}
}

func TestValidateWorkflowSpecNilName(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "",
		States: []State{
			{
				Name:     "Test",
				Type:     StateTypeTask,
				Resource: "CloneRepoActivity",
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if result.Valid {
		t.Error("Spec with empty name should be invalid")
	}

	if len(result.Errors) == 0 {
		t.Error("Should have validation errors")
	}
}

func TestValidateWorkflowSpecNoStates(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name:   "test",
		States: []State{},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if result.Valid {
		t.Error("Spec with no states should be invalid")
	}
}

func TestValidateInvalidStateTransition(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test",
		States: []State{
			{
				Name:     "A",
				Type:     StateTypeTask,
				Resource: "CloneRepoActivity",
				Next:     "NonExistent",
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if result.Valid {
		t.Error("Spec with invalid state transition should be invalid")
	}
}

func TestValidateDuplicateStateName(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test",
		States: []State{
			{
				Name:     "A",
				Type:     StateTypeTask,
				Resource: "CloneRepoActivity",
			},
			{
				Name:     "A", // Duplicate!
				Type:     StateTypeTask,
				Resource: "CloneRepoActivity",
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if result.Valid {
		t.Error("Spec with duplicate state names should be invalid")
	}
}

func TestValidateUnknownActivity(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test",
		States: []State{
			{
				Name:     "A",
				Type:     StateTypeTask,
				Resource: "UnknownActivity",
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if result.Valid {
		t.Error("Spec with unknown activity should be invalid")
	}
}

func TestValidatePassState(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test",
		States: []State{
			{
				Name:   "Success",
				Type:   StateTypePass,
				Result: map[string]interface{}{"status": "ok"},
				End:    true,
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if !result.Valid {
		t.Errorf("Pass state spec should be valid: %v", result.Errors)
	}
}

func TestValidatePassStateNoResult(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test",
		States: []State{
			{
				Name: "Success",
				Type: StateTypePass,
				End:  true,
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if result.Valid {
		t.Error("Pass state without result should be invalid")
	}
}

func TestValidateFailState(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test",
		States: []State{
			{
				Name:  "Fail",
				Type:  StateTypeFail,
				Error: "TestError",
				Cause: "For testing",
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if !result.Valid {
		t.Errorf("Fail state spec should be valid: %v", result.Errors)
	}
}

func TestValidateInvalidDuration(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &WorkflowSpec{
		Name: "test",
		States: []State{
			{
				Name:     "A",
				Type:     StateTypeTask,
				Resource: "CloneRepoActivity",
				Timeout:  "invalid",
			},
		},
	}

	result := validator.ValidateWorkflowSpec(spec)
	if result.Valid {
		t.Error("Spec with invalid timeout should be invalid")
	}
}

func TestValidateCronWorkflowSpec(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &CronWorkflowSpec{
		Name:          "daily-scan",
		Type:          "CronWorkflow",
		Schedule:      "0 2 * * *",
		Timezone:      "UTC",
		MaxConcurrent: 1,
		States: []State{
			{
				Name:     "Scan",
				Type:     StateTypeTask,
				Resource: "SecurityScanActivity",
				End:      true,
			},
		},
	}

	result := validator.ValidateCronWorkflowSpec(spec)
	if !result.Valid {
		t.Errorf("Valid cron spec should pass: %v", result.Errors)
	}
}

func TestValidateCronWorkflowSpecInvalidTimezone(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &CronWorkflowSpec{
		Name:          "daily-scan",
		Type:          "CronWorkflow",
		Schedule:      "0 2 * * *",
		Timezone:      "InvalidTimezone",
		MaxConcurrent: 1,
		States: []State{
			{
				Name:     "Scan",
				Type:     StateTypeTask,
				Resource: "SecurityScanActivity",
				End:      true,
			},
		},
	}

	result := validator.ValidateCronWorkflowSpec(spec)
	if result.Valid {
		t.Error("Cron spec with invalid timezone should be invalid")
	}
}

func TestValidateCronWorkflowSpecInvalidSchedule(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &CronWorkflowSpec{
		Name:          "daily-scan",
		Type:          "CronWorkflow",
		Schedule:      "invalid cron",
		Timezone:      "UTC",
		MaxConcurrent: 1,
		States: []State{
			{
				Name:     "Scan",
				Type:     StateTypeTask,
				Resource: "SecurityScanActivity",
				End:      true,
			},
		},
	}

	result := validator.ValidateCronWorkflowSpec(spec)
	if result.Valid {
		t.Error("Cron spec with invalid schedule should be invalid")
	}
}

func TestValidateCronWorkflowSpecInvalidType(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base not found")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load KB: %v", err)
	}

	validator := NewValidator(kb)

	spec := &CronWorkflowSpec{
		Name:          "daily-scan",
		Type:          "WrongType",
		Schedule:      "0 2 * * *",
		Timezone:      "UTC",
		MaxConcurrent: 1,
		States: []State{
			{
				Name:     "Scan",
				Type:     StateTypeTask,
				Resource: "SecurityScanActivity",
				End:      true,
			},
		},
	}

	result := validator.ValidateCronWorkflowSpec(spec)
	if result.Valid {
		t.Error("Cron spec with wrong type should be invalid")
	}
}

func TestValidateDuration(t *testing.T) {
	validDurations := []string{"1s", "5m", "1h", "100ms"}
	for _, dur := range validDurations {
		if err := validateDuration(dur); err != nil {
			t.Errorf("Duration %s should be valid: %v", dur, err)
		}
	}

	invalidDurations := []string{"invalid", "5x", ""}
	for _, dur := range invalidDurations {
		if err := validateDuration(dur); err == nil {
			t.Errorf("Duration %s should be invalid", dur)
		}
	}
}

func TestValidateCronExpression(t *testing.T) {
	validCrons := []string{
		"0 2 * * *",     // 2 AM daily
		"*/5 * * * *",   // Every 5 minutes
		"0 0 1 * *",     // First of month
		"0 12 * * 1",    // Noon on Mondays
		"30 15 * * *",   // 3:30 PM daily
	}

	for _, cron := range validCrons {
		if err := validateCronExpression(cron); err != nil {
			t.Errorf("Cron %s should be valid: %v", cron, err)
		}
	}

	invalidCrons := []string{
		"invalid",         // Too few fields
		"0 2 * * * *",     // Too many fields
		"60 * * * *",      // Invalid minute
		"* 25 * * *",      // Invalid hour
	}

	for _, cron := range invalidCrons {
		if err := validateCronExpression(cron); err == nil {
			t.Errorf("Cron %s should be invalid", cron)
		}
	}
}

func TestValidationResultString(t *testing.T) {
	result := &ValidationResult{
		Valid:  true,
		Errors: []ValidationError{},
	}

	str := result.String()
	if str != "Valid ✓" {
		t.Errorf("Valid result string should be 'Valid ✓', got: %s", str)
	}

	result.Valid = false
	result.Errors = []ValidationError{
		{
			Path:    "spec.name",
			Message: "name is required",
		},
	}

	str = result.String()
	if !contains(str, "Invalid") {
		t.Error("Invalid result string should contain 'Invalid'")
	}
}
