package provider

import (
	"encoding/json"
	"strings"
	"testing"
)

func TestResponsesToChatCompletion_StringInput(t *testing.T) {
	body := []byte(`{"model":"gpt-4o-mini","instructions":"Be brief","input":"Hello"}`)
	out, err := ResponsesToChatCompletion(body)
	if err != nil {
		t.Fatal(err)
	}
	var req map[string]any
	if err := json.Unmarshal(out, &req); err != nil {
		t.Fatal(err)
	}
	if req["model"] != "gpt-4o-mini" {
		t.Fatalf("model: %v", req["model"])
	}
	msgs := req["messages"].([]any)
	if len(msgs) != 2 {
		t.Fatalf("messages len: %d", len(msgs))
	}
	sys := msgs[0].(map[string]any)
	user := msgs[1].(map[string]any)
	if sys["role"] != "system" || sys["content"] != "Be brief" {
		t.Fatalf("system: %#v", sys)
	}
	if user["role"] != "user" || user["content"] != "Hello" {
		t.Fatalf("user: %#v", user)
	}
}

func TestChatCompletionToResponses(t *testing.T) {
	body := []byte(`{"id":"chatcmpl-abc123","model":"gpt-4o-mini","created":123,"choices":[{"message":{"role":"assistant","content":"Hi"}}],"usage":{"prompt_tokens":3,"completion_tokens":1,"total_tokens":4}}`)
	out, err := ChatCompletionToResponses(body)
	if err != nil {
		t.Fatal(err)
	}
	var resp map[string]any
	if err := json.Unmarshal(out, &resp); err != nil {
		t.Fatal(err)
	}
	if resp["object"] != "response" {
		t.Fatalf("object: %v", resp["object"])
	}
	if resp["id"] != "resp_abc123" {
		t.Fatalf("id: %v", resp["id"])
	}
	if resp["output_text"] != "Hi" {
		t.Fatalf("output_text: %v", resp["output_text"])
	}
	output := resp["output"].([]any)
	msg := output[0].(map[string]any)
	content := msg["content"].([]any)
	text := content[0].(map[string]any)
	if text["type"] != "output_text" || text["text"] != "Hi" {
		t.Fatalf("text: %#v", text)
	}
	if _, ok := text["annotations"]; !ok {
		t.Fatalf("missing annotations: %#v", text)
	}
	usage := resp["usage"].(map[string]any)
	if usage["input_tokens"].(float64) != 3 {
		t.Fatalf("usage: %#v", usage)
	}
	if _, ok := usage["input_tokens_details"]; !ok {
		t.Fatalf("missing input_tokens_details")
	}
}

func TestResponsesToChatCompletion_InputTextParts(t *testing.T) {
	body := []byte(`{
		"model":"gpt-4o-mini",
		"input":[{"role":"user","content":[{"type":"input_text","text":"Hello"}]}]
	}`)
	out, err := ResponsesToChatCompletion(body)
	if err != nil {
		t.Fatal(err)
	}
	var req map[string]any
	if err := json.Unmarshal(out, &req); err != nil {
		t.Fatal(err)
	}
	msgs := req["messages"].([]any)
	user := msgs[0].(map[string]any)
	if user["content"] != "Hello" {
		t.Fatalf("content: %#v", user["content"])
	}
}

func TestResponsesToChatCompletion_InputTextAndImage(t *testing.T) {
	body := []byte(`{
		"model":"gpt-4o-mini",
		"input":[{"role":"user","content":[
			{"type":"input_text","text":"describe"},
			{"type":"input_image","image_url":"https://example.com/a.png","detail":"auto"}
		]}]
	}`)
	out, err := ResponsesToChatCompletion(body)
	if err != nil {
		t.Fatal(err)
	}
	var req map[string]any
	if err := json.Unmarshal(out, &req); err != nil {
		t.Fatal(err)
	}
	msgs := req["messages"].([]any)
	user := msgs[0].(map[string]any)
	parts := user["content"].([]any)
	if len(parts) != 2 {
		t.Fatalf("parts: %#v", parts)
	}
	textPart := parts[0].(map[string]any)
	if textPart["type"] != "text" || textPart["text"] != "describe" {
		t.Fatalf("text part: %#v", textPart)
	}
	imgPart := parts[1].(map[string]any)
	if imgPart["type"] != "image_url" {
		t.Fatalf("image part: %#v", imgPart)
	}
}

func TestResponsesToChatCompletion_MessageItem(t *testing.T) {
	body := []byte(`{
		"model":"gpt-4o-mini",
		"input":[{"type":"message","role":"user","content":[{"type":"input_text","text":"Hi"}]}]
	}`)
	out, err := ResponsesToChatCompletion(body)
	if err != nil {
		t.Fatal(err)
	}
	if strings.Contains(string(out), "input_text") {
		t.Fatalf("should not contain input_text: %s", out)
	}
	var req map[string]any
	if err := json.Unmarshal(out, &req); err != nil {
		t.Fatal(err)
	}
	msgs := req["messages"].([]any)
	user := msgs[0].(map[string]any)
	if user["content"] != "Hi" {
		t.Fatalf("content: %#v", user["content"])
	}
}

func TestAdaptResponsesStream(t *testing.T) {
	upstream := strings.NewReader("data: {\"id\":\"chatcmpl-1\",\"model\":\"gpt-4o-mini\",\"choices\":[{\"delta\":{\"content\":\"Hi\"}}]}\n\ndata: [DONE]\n\n")
	var out strings.Builder
	result, err := AdaptResponsesStream([]byte(`{"model":"gpt-4o-mini","stream":true}`), upstream, &out, nil)
	if err != nil {
		t.Fatal(err)
	}
	if result.StatusCode != 200 {
		t.Fatalf("status: %d", result.StatusCode)
	}
	s := out.String()
	for _, event := range []string{
		"response.created",
		"response.in_progress",
		"response.output_item.added",
		"response.output_text.delta",
		"response.output_text.done",
		"response.output_item.done",
		"response.completed",
	} {
		if !strings.Contains(s, event) {
			t.Fatalf("missing event %s: %s", event, s)
		}
	}
	if !strings.Contains(s, `"delta":"Hi"`) {
		t.Fatalf("missing delta text: %s", s)
	}
	if !strings.Contains(s, `"output_text":"Hi"`) {
		t.Fatalf("missing output_text in completed: %s", s)
	}
}
