package workflow

import (
	"testing"
)

func TestParseParamDeclaration(t *testing.T) {
	tests := []struct {
		name        string
		declaration string
		expected    *ParamDeclaration
		shouldError bool
	}{
		{
			name:        "simple string param",
			declaration: "userId(STRING)",
			expected: &ParamDeclaration{
				Name: "userId",
				Type: "STRING",
			},
			shouldError: false,
		},
		{
			name:        "int param",
			declaration: "maxLimit(INT)",
			expected: &ParamDeclaration{
				Name: "maxLimit",
				Type: "INT",
			},
			shouldError: false,
		},
		{
			name:        "object param",
			declaration: "config(OBJECT)",
			expected: &ParamDeclaration{
				Name: "config",
				Type: "OBJECT",
			},
			shouldError: false,
		},
		{
			name:        "array param",
			declaration: "items([STRING])",
			expected: &ParamDeclaration{
				Name: "items",
				Type: "[STRING]",
			},
			shouldError: false,
		},
		{
			name:        "invalid - starts with $",
			declaration: "$userId(STRING)",
			expected:    nil,
			shouldError: true,
		},
		{
			name:        "invalid - starts with underscore",
			declaration: "_local(STRING)",
			expected:    nil,
			shouldError: true,
		},
		{
			name:        "invalid - missing type",
			declaration: "userId",
			expected:    nil,
			shouldError: true,
		},
		{
			name:        "invalid - missing parentheses",
			declaration: "userIdSTRING",
			expected:    nil,
			shouldError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := ParseParamDeclaration(tt.declaration)

			if tt.shouldError {
				if err == nil {
					t.Fatal("expected error but got none")
				}
				return
			}

			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}

			if result.Name != tt.expected.Name {
				t.Errorf("expected Name=%s, got %s", tt.expected.Name, result.Name)
			}

			if result.Type != tt.expected.Type {
				t.Errorf("expected Type=%s, got %s", tt.expected.Type, result.Type)
			}
		})
	}
}

func TestGetParamDeclarations(t *testing.T) {
	registry := &Registry{
		Params: []string{
			"userId(STRING)",
			"maxLimit(INT)",
			"config(OBJECT)",
		},
	}

	params, err := registry.GetParamDeclarations()
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if len(params) != 3 {
		t.Fatalf("expected 3 parameters, got %d", len(params))
	}

	// Check userId
	if params["userId"] == nil {
		t.Error("userId parameter not found")
	} else {
		if params["userId"].Type != "STRING" {
			t.Errorf("expected userId type STRING, got %s", params["userId"].Type)
		}
	}

	// Check maxLimit
	if params["maxLimit"] == nil {
		t.Error("maxLimit parameter not found")
	} else {
		if params["maxLimit"].Type != "INT" {
			t.Errorf("expected maxLimit type INT, got %s", params["maxLimit"].Type)
		}
	}

	// Check config
	if params["config"] == nil {
		t.Error("config parameter not found")
	} else {
		if params["config"].Type != "OBJECT" {
			t.Errorf("expected config type OBJECT, got %s", params["config"].Type)
		}
	}
}

func TestValidateRegistryWithParams(t *testing.T) {
	t.Run("valid registry with params", func(t *testing.T) {
		registry := &Registry{
			Params: []string{
				"userId(STRING)",
				"maxLimit(INT)",
			},
			Vars: []string{
				"$result(STRING)",
			},
		}

		err := registry.ValidateRegistry()
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
	})

	t.Run("duplicate parameter names", func(t *testing.T) {
		registry := &Registry{
			Params: []string{
				"userId(STRING)",
				"userId(INT)",
			},
		}

		err := registry.ValidateRegistry()
		if err == nil {
			t.Fatal("expected error for duplicate parameter names")
		}
	})

	t.Run("invalid parameter format", func(t *testing.T) {
		registry := &Registry{
			Params: []string{
				"invalidFormat",
			},
		}

		err := registry.ValidateRegistry()
		if err == nil {
			t.Fatal("expected error for invalid parameter format")
		}
	})
}
