package workflow

import (
	"encoding/json"
	"testing"
)

func TestIsAnthropicModel(t *testing.T) {
	tests := []struct {
		model    string
		expected bool
	}{
		{"claude-3-opus-20240229", true},
		{"claude-3-sonnet", true},
		{"claude-3-haiku", true},
		{"anthropic/claude-3-opus", true},
		{"Claude-3-Opus", true},
		{"gpt-4", false},
		{"gpt-4-turbo", false},
		{"gemini-pro", false},
		{"mistral-large", false},
	}

	for _, tc := range tests {
		t.Run(tc.model, func(t *testing.T) {
			if got := isAnthropicModel(tc.model); got != tc.expected {
				t.Errorf("isAnthropicModel(%q) = %v, want %v", tc.model, got, tc.expected)
			}
		})
	}
}

func TestBuildRequestModelOverride(t *testing.T) {
	t.Run("ConfigModelOverridesParamModel", func(t *testing.T) {
		adapter := NewOpenAIAdapter(OpenAIConfig{Model: "claude-3-opus"})

		params := map[string]interface{}{
			"model":    "gpt-4",
			"messages": []interface{}{},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}
		if req.Model != "claude-3-opus" {
			t.Errorf("Expected model 'claude-3-opus', got %q", req.Model)
		}
	})

	t.Run("NoOverrideUsesParamModel", func(t *testing.T) {
		adapter := NewOpenAIAdapter(OpenAIConfig{})

		params := map[string]interface{}{
			"model":    "gpt-4",
			"messages": []interface{}{},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}
		if req.Model != "gpt-4" {
			t.Errorf("Expected model 'gpt-4', got %q", req.Model)
		}
	})
}

func TestBuildRequestCacheControlOverride(t *testing.T) {
	boolPtr := func(b bool) *bool { return &b }

	t.Run("ConfigCacheControlOverridesParam", func(t *testing.T) {
		adapter := NewOpenAIAdapter(OpenAIConfig{CacheControl: boolPtr(true)})

		params := map[string]interface{}{
			"model":         "claude-3-opus-20240229",
			"cache_control": false,
			"messages": []interface{}{
				map[string]interface{}{"role": "system", "content": "You are helpful."},
			},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}
		if req.Messages[0].CacheControl == nil {
			t.Fatal("Expected cache_control on system message when config override is true")
		}
	})

	t.Run("ConfigCacheControlDisablesParam", func(t *testing.T) {
		adapter := NewOpenAIAdapter(OpenAIConfig{CacheControl: boolPtr(false)})

		params := map[string]interface{}{
			"model":         "claude-3-opus-20240229",
			"cache_control": true,
			"messages": []interface{}{
				map[string]interface{}{"role": "system", "content": "You are helpful."},
			},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}
		if req.Messages[0].CacheControl != nil {
			t.Error("Expected no cache_control when config override is false")
		}
	})

	t.Run("NilConfigFallsToParam", func(t *testing.T) {
		adapter := NewOpenAIAdapter(OpenAIConfig{})

		params := map[string]interface{}{
			"model":         "claude-3-opus-20240229",
			"cache_control": true,
			"messages": []interface{}{
				map[string]interface{}{"role": "system", "content": "You are helpful."},
			},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}
		if req.Messages[0].CacheControl == nil {
			t.Fatal("Expected cache_control from param when config is nil")
		}
	})
}

func TestBuildRequestAPIKey(t *testing.T) {
	t.Run("RequestAPIKeySetInBody", func(t *testing.T) {
		adapter := NewOpenAIAdapter(OpenAIConfig{RequestAPIKey: "sk-user-key-123"})

		params := map[string]interface{}{
			"model":    "gpt-4",
			"messages": []interface{}{},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}
		if req.APIKey != "sk-user-key-123" {
			t.Errorf("Expected api_key 'sk-user-key-123', got %q", req.APIKey)
		}

		// Verify JSON output includes api_key
		body, _ := json.Marshal(req)
		if !contains(string(body), `"api_key":"sk-user-key-123"`) {
			t.Errorf("Expected api_key in JSON body, got: %s", string(body))
		}
	})

	t.Run("NoRequestAPIKeyOmittedFromBody", func(t *testing.T) {
		adapter := NewOpenAIAdapter(OpenAIConfig{})

		params := map[string]interface{}{
			"model":    "gpt-4",
			"messages": []interface{}{},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}
		if req.APIKey != "" {
			t.Errorf("Expected empty api_key, got %q", req.APIKey)
		}

		// Verify JSON output does NOT include api_key
		body, _ := json.Marshal(req)
		if contains(string(body), `"api_key"`) {
			t.Errorf("Expected no api_key in JSON body, got: %s", string(body))
		}
	})
}

func TestBuildRequestCacheControl(t *testing.T) {
	adapter := NewOpenAIAdapter(OpenAIConfig{})

	t.Run("AnthropicWithCacheControl", func(t *testing.T) {
		params := map[string]interface{}{
			"model":         "claude-3-opus-20240229",
			"cache_control": true,
			"messages": []interface{}{
				map[string]interface{}{"role": "system", "content": "You are helpful."},
				map[string]interface{}{"role": "user", "content": "Hello"},
			},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}

		// System message should have cache_control
		if req.Messages[0].CacheControl == nil {
			t.Fatal("Expected cache_control on system message")
		}
		if req.Messages[0].CacheControl.Type != "ephemeral" {
			t.Errorf("Expected cache_control type 'ephemeral', got %q", req.Messages[0].CacheControl.Type)
		}

		// User message should NOT have cache_control
		if req.Messages[1].CacheControl != nil {
			t.Error("Expected no cache_control on user message")
		}

		// Verify JSON output includes cache_control
		body, _ := json.Marshal(req)
		if !contains(string(body), `"cache_control":{"type":"ephemeral"}`) {
			t.Errorf("Expected cache_control in JSON, got: %s", string(body))
		}
	})

	t.Run("AnthropicWithoutCacheControl", func(t *testing.T) {
		params := map[string]interface{}{
			"model": "claude-3-opus-20240229",
			"messages": []interface{}{
				map[string]interface{}{"role": "system", "content": "You are helpful."},
			},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}

		if req.Messages[0].CacheControl != nil {
			t.Error("Expected no cache_control when option not set")
		}
	})

	t.Run("NonAnthropicWithCacheControl", func(t *testing.T) {
		params := map[string]interface{}{
			"model":         "gpt-4",
			"cache_control": true,
			"messages": []interface{}{
				map[string]interface{}{"role": "system", "content": "You are helpful."},
			},
		}

		req, err := adapter.buildRequest(params)
		if err != nil {
			t.Fatalf("buildRequest failed: %v", err)
		}

		if req.Messages[0].CacheControl != nil {
			t.Error("Expected no cache_control for non-Anthropic model")
		}
	})
}

func contains(s, substr string) bool {
	return len(s) >= len(substr) && searchString(s, substr)
}

func searchString(s, substr string) bool {
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}
