package ai

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

type anthropicMockConfig struct {
	baseURL       string
	password      string
	model         string
	temperature   float32
	topP          float32
	topK          int32
	maxTokens     int
	stopSequences []string
	customHeaders []http.Header
}

func (m *anthropicMockConfig) GetPassword() string             { return m.password }
func (m *anthropicMockConfig) GetModel() string                { return m.model }
func (m *anthropicMockConfig) GetBaseURL() string              { return m.baseURL }
func (m *anthropicMockConfig) GetProxyEndpoint() string        { return "" }
func (m *anthropicMockConfig) GetEndpointName() string         { return "" }
func (m *anthropicMockConfig) GetEngine() string               { return "" }
func (m *anthropicMockConfig) GetTemperature() float32         { return m.temperature }
func (m *anthropicMockConfig) GetProviderRegion() string       { return "" }
func (m *anthropicMockConfig) GetTopP() float32                { return m.topP }
func (m *anthropicMockConfig) GetTopK() int32                  { return m.topK }
func (m *anthropicMockConfig) GetMaxTokens() int               { return m.maxTokens }
func (m *anthropicMockConfig) GetStopSequences() []string      { return m.stopSequences }
func (m *anthropicMockConfig) GetProviderId() string           { return "" }
func (m *anthropicMockConfig) GetCompartmentId() string        { return "" }
func (m *anthropicMockConfig) GetOrganizationId() string       { return "" }
func (m *anthropicMockConfig) GetAzureAPIType() string         { return "" }
func (m *anthropicMockConfig) GetAzureAPIVersion() string      { return "" }
func (m *anthropicMockConfig) GetCustomHeaders() []http.Header { return m.customHeaders }

func TestAnthropicClientGetCompletion(t *testing.T) {
	type requestBody struct {
		Model         string   `json:"model"`
		MaxTokens     int      `json:"max_tokens"`
		Temperature   float32  `json:"temperature"`
		TopP          float32  `json:"top_p"`
		TopK          int32    `json:"top_k"`
		StopSequences []string `json:"stop_sequences"`
		Messages      []struct {
			Role    string `json:"role"`
			Content []struct {
				Type string `json:"type"`
				Text string `json:"text"`
			} `json:"content"`
		} `json:"messages"`
	}

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, "/v1/messages", r.URL.Path)
		assert.Equal(t, "test-token", r.Header.Get("X-Api-Key"))
		assert.NotEmpty(t, r.Header.Get("Anthropic-Version"))
		assert.Equal(t, "test-value", r.Header.Get("X-Test-Header"))

		var body requestBody
		require.NoError(t, json.NewDecoder(r.Body).Decode(&body))
		assert.Equal(t, "claude-test", body.Model)
		assert.Equal(t, 1024, body.MaxTokens)
		assert.Equal(t, float32(0.1), body.Temperature)
		assert.Equal(t, float32(0.8), body.TopP)
		assert.Equal(t, int32(25), body.TopK)
		assert.Equal(t, []string{"STOP"}, body.StopSequences)
		require.Len(t, body.Messages, 1)
		assert.Equal(t, "user", body.Messages[0].Role)
		require.Len(t, body.Messages[0].Content, 1)
		assert.Equal(t, "text", body.Messages[0].Content[0].Type)
		assert.Equal(t, "hello cluster", body.Messages[0].Content[0].Text)

		w.Header().Set("Content-Type", "application/json")
		_, err := w.Write([]byte(`{"content":[{"type":"text","text":"diagnosis"}]}`))
		require.NoError(t, err)
	}))
	defer server.Close()

	client := &AnthropicClient{}
	err := client.Configure(&anthropicMockConfig{
		baseURL:       server.URL,
		password:      "test-token",
		model:         "claude-test",
		temperature:   0.1,
		topP:          0.8,
		topK:          25,
		maxTokens:     1024,
		stopSequences: []string{"STOP"},
		customHeaders: []http.Header{{"X-Test-Header": []string{"test-value"}}},
	})
	require.NoError(t, err)

	completion, err := client.GetCompletion(context.Background(), "hello cluster")
	require.NoError(t, err)
	assert.Equal(t, "diagnosis", completion)
}

func TestAnthropicClientHonorsExplicitMessagesURLAndDefaultModel(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, "/custom/v1/messages", r.URL.Path)
		w.Header().Set("Content-Type", "application/json")
		_, err := w.Write([]byte(`{"content":[{"type":"text","text":"ok"}]}`))
		require.NoError(t, err)
	}))
	defer server.Close()

	client := &AnthropicClient{}
	err := client.Configure(&anthropicMockConfig{
		baseURL:   server.URL + "/custom/v1/messages",
		password:  "test-token",
		maxTokens: 0,
	})
	require.NoError(t, err)
	assert.Equal(t, anthropicDefaultModel, client.model)
	assert.Equal(t, anthropicDefaultMaxTokens, client.maxTokens)

	completion, err := client.GetCompletion(context.Background(), "hello")
	require.NoError(t, err)
	assert.Equal(t, "ok", completion)
}

func TestAnthropicClientReturnsStructuredErrors(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusBadRequest)
		_, err := w.Write([]byte(`{"error":{"type":"invalid_request_error","message":"bad prompt"}}`))
		require.NoError(t, err)
	}))
	defer server.Close()

	client := &AnthropicClient{}
	err := client.Configure(&anthropicMockConfig{baseURL: server.URL, password: "test-token"})
	require.NoError(t, err)

	_, err = client.GetCompletion(context.Background(), "hello")
	require.Error(t, err)
	assert.Contains(t, err.Error(), "bad prompt")
}
