package interpreter

import (
	"encoding/json"
	"testing"

	mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp"
)

// TestMcpResultToValue tests converting MCP results to Values
func TestMcpResultToValue(t *testing.T) {
	tests := []struct {
		name     string
		result   *mcpsdk.CallToolResult
		wantType ValueType
		wantStr  string
		wantErr  bool
	}{
		{
			name:     "nil result",
			result:   nil,
			wantType: ValueTypeNull,
		},
		{
			name: "empty content array",
			result: &mcpsdk.CallToolResult{
				Content: []mcpsdk.Content{},
			},
			wantType: ValueTypeNull,
		},
		{
			name: "single text content",
			result: &mcpsdk.CallToolResult{
				Content: []mcpsdk.Content{
					createTextContent("Hello from MCP"),
				},
			},
			wantType: ValueTypeString,
			wantStr:  "Hello from MCP",
		},
		{
			name: "multiple text content items",
			result: &mcpsdk.CallToolResult{
				Content: []mcpsdk.Content{
					createTextContent("First"),
					createTextContent("Second"),
				},
			},
			wantType: ValueTypeArray,
		},
		{
			name: "structured content",
			result: &mcpsdk.CallToolResult{
				StructuredContent: map[string]interface{}{
					"name":  "Alice",
					"age":   30,
					"email": "alice@example.com",
				},
			},
			wantType: ValueTypeObject,
		},
		{
			name: "structured content with array",
			result: &mcpsdk.CallToolResult{
				StructuredContent: map[string]interface{}{
					"items": []interface{}{"a", "b", "c"},
					"count": 3,
				},
			},
			wantType: ValueTypeObject,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := mcpResultToValue(tt.result)
			if (err != nil) != tt.wantErr {
				t.Errorf("mcpResultToValue() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if err != nil {
				return
			}

			if got.Type() != tt.wantType {
				t.Errorf("mcpResultToValue() type = %v, want %v", got.Type(), tt.wantType)
			}

			if tt.wantStr != "" {
				if got.String() != tt.wantStr {
					t.Errorf("mcpResultToValue() string = %v, want %v", got.String(), tt.wantStr)
				}
			}
		})
	}
}

// TestContentToValue tests converting individual MCP content items to Values
func TestContentToValue(t *testing.T) {
	tests := []struct {
		name     string
		content  mcpsdk.Content
		wantType ValueType
		wantStr  string
		wantErr  bool
	}{
		{
			name:     "text content",
			content:  createTextContent("Test message"),
			wantType: ValueTypeString,
			wantStr:  "Test message",
		},
		{
			name:     "image content",
			content:  createImageContent("base64data", "image/png"),
			wantType: ValueTypeObject,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := contentToValue(tt.content)
			if (err != nil) != tt.wantErr {
				t.Errorf("contentToValue() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if err != nil {
				return
			}

			if got.Type() != tt.wantType {
				t.Errorf("contentToValue() type = %v, want %v", got.Type(), tt.wantType)
			}

			if tt.wantStr != "" {
				if got.String() != tt.wantStr {
					t.Errorf("contentToValue() string = %v, want %v", got.String(), tt.wantStr)
				}
			}
		})
	}
}

// TestValueToInterface tests converting Values to interface{} for MCP calls
func TestValueToInterface(t *testing.T) {
	tests := []struct {
		name string
		val  Value
		want interface{}
	}{
		{
			name: "null value",
			val:  &NullValue{},
			want: nil,
		},
		{
			name: "bool value",
			val:  &BoolValue{Value: true},
			want: true,
		},
		{
			name: "number value",
			val:  &NumberValue{Value: 42.5},
			want: 42.5,
		},
		{
			name: "string value",
			val:  &StringValue{Value: "hello"},
			want: "hello",
		},
		{
			name: "array value",
			val: &ArrayValue{
				Elements: []Value{
					&StringValue{Value: "a"},
					&NumberValue{Value: 1},
				},
			},
			want: []interface{}{"a", float64(1)},
		},
		{
			name: "object value",
			val: &ObjectValue{
				Properties: map[string]*PropertyDescriptor{
					"name": {Value: &StringValue{Value: "Alice"}},
					"age":  {Value: &NumberValue{Value: 30}},
				},
			},
			want: map[string]interface{}{
				"name": "Alice",
				"age":  float64(30),
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ValueToInterface(tt.val)

			// Use JSON marshaling for deep equality check
			gotJSON, _ := json.Marshal(got)
			wantJSON, _ := json.Marshal(tt.want)

			if string(gotJSON) != string(wantJSON) {
				t.Errorf("ValueToInterface() = %v, want %v", string(gotJSON), string(wantJSON))
			}
		})
	}
}

// TestCallMCPTool tests the callMCPTool function with various argument patterns
func TestCallMCPTool(t *testing.T) {
	// Note: These tests verify the argument processing logic,
	// but skip actual MCP server calls since we don't have a real server

	tests := []struct {
		name    string
		input   string
		wantErr bool
	}{
		{
			name: "call with no arguments",
			input: `
mcp test {
	command: "echo",
	args: [],
}
`,
			wantErr: true, // Will fail when trying to connect
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// This is a placeholder - actual MCP tool calls require a server
			// The real integration tests would go here
			if !tt.wantErr {
				t.Skip("Skipping test that requires actual MCP server")
			}
		})
	}
}

// Helper functions to create MCP content types for testing
func createTextContent(text string) mcpsdk.Content {
	return &mcpsdk.TextContent{
		Text: text,
	}
}

func createImageContent(data, mimeType string) mcpsdk.Content {
	return &mcpsdk.ImageContent{
		Data:     []byte(data),
		MIMEType: mimeType,
	}
}
