package ai

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

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

func TestExtractChatContent_String(t *testing.T) {
	raw := []byte(`{"model":"grok-3","choices":[{"finish_reason":"stop","message":{"content":"你好世界"}}]}`)
	text, meta, err := extractChatContent(raw)
	require.NoError(t, err)
	require.Equal(t, "你好世界", text)
	require.Equal(t, "stop", meta.FinishReason)
}

func TestCompleteContinuesLengthResponseWithoutOverlap(t *testing.T) {
	calls := 0
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		calls++
		w.Header().Set("Content-Type", "application/json")
		if calls == 1 {
			_, _ = fmt.Fprint(w, `{"model":"grok-3","choices":[{"finish_reason":"length","message":{"content":"第一段，還沒"}}]}`)
			return
		}
		_, _ = fmt.Fprint(w, `{"model":"grok-3","choices":[{"finish_reason":"stop","message":{"content":"還沒講完。第二段。"}}]}`)
	}))
	defer server.Close()

	client := NewOpenAICompatible(ProviderXAI, server.URL)
	text, err := client.Complete(context.Background(), "key", "grok-3", "寫完整")
	require.NoError(t, err)
	require.Equal(t, "第一段，還沒講完。第二段。", text)
	require.Equal(t, 2, calls)
}

func TestExtractStreamEventFinishReason(t *testing.T) {
	chunk, finish, ok := extractStreamEvent(`{"choices":[{"finish_reason":"length","delta":{}}]}`)
	require.True(t, ok)
	require.Empty(t, chunk)
	require.Equal(t, "length", finish)
}

func TestCompleteStreamContinuesLengthResponse(t *testing.T) {
	calls := 0
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		calls++
		if calls == 1 {
			w.Header().Set("Content-Type", "text/event-stream")
			_, _ = fmt.Fprint(w, "data: {\"choices\":[{\"delta\":{\"content\":\"第一段，還沒\"}}]}\n\n")
			_, _ = fmt.Fprint(w, "data: {\"choices\":[{\"finish_reason\":\"length\",\"delta\":{}}]}\n\n")
			_, _ = fmt.Fprint(w, "data: [DONE]\n\n")
			return
		}
		w.Header().Set("Content-Type", "application/json")
		_, _ = fmt.Fprint(w, `{"model":"grok-3","choices":[{"finish_reason":"stop","message":{"content":"還沒講完。第二段。"}}]}`)
	}))
	defer server.Close()

	client := NewOpenAICompatible(ProviderXAI, server.URL)
	var streamed strings.Builder
	text, err := client.CompleteStream(context.Background(), "key", "grok-3", "寫完整", func(chunk string) error {
		streamed.WriteString(chunk)
		return nil
	})
	require.NoError(t, err)
	require.Equal(t, "第一段，還沒講完。第二段。", text)
	require.Equal(t, text, streamed.String())
	require.Equal(t, 2, calls)
}

func TestExtractChatContent_ArrayParts(t *testing.T) {
	raw := []byte(`{"choices":[{"message":{"content":[{"type":"text","text":"第一段"},{"type":"text","text":"第二段"}]}}]}`)
	text, _, err := extractChatContent(raw)
	require.NoError(t, err)
	require.Contains(t, text, "第一段")
	require.Contains(t, text, "第二段")
}

func TestExtractChatContent_Empty(t *testing.T) {
	raw := []byte(`{"choices":[{"finish_reason":"length","message":{"content":""}}]}`)
	text, meta, err := extractChatContent(raw)
	require.NoError(t, err)
	require.Equal(t, "", text)
	require.Equal(t, "length", meta.FinishReason)
}

func TestExtractChatContent_IgnoresReasoningOnly(t *testing.T) {
	// deepseek / kimi 思考模型常只回 reasoning_content；不可當聊天回覆
	raw := []byte(`{"choices":[{"finish_reason":"length","message":{"content":null,"reasoning_content":"我們需要根據最近的對話來回應…"}}]}`)
	text, meta, err := extractChatContent(raw)
	require.NoError(t, err)
	require.Equal(t, "", text)
	require.Equal(t, "length", meta.FinishReason)
}
