package clients

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

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
)

func TestOpenAIChatNativeDeepPassthroughPreservesOfficialAndFutureFields(t *testing.T) {
	requestBody := completeChatPassthroughBody()
	var captured map[string]any
	var idempotencyKey string
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		idempotencyKey = r.Header.Get("Idempotency-Key")
		if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
			t.Fatal(err)
		}
		_ = json.NewEncoder(w).Encode(map[string]any{
			"id": "chatcmpl-native", "object": "chat.completion", "model": "provider-chat",
			"choices": []any{map[string]any{"message": map[string]any{"role": "assistant", "content": "ok"}}},
		})
	}))
	defer server.Close()

	_, err := (OpenAIClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
		Kind: "chat.completions", Model: "public-chat", Body: requestBody, OriginalBody: requestBody,
		UpstreamIdempotencyKey: "gateway-task-id",
		Candidate: store.RuntimeModelCandidate{
			Provider: "openai", BaseURL: server.URL, ProviderModelName: "provider-chat",
			Credentials: map[string]any{"apiKey": "test-key"},
		},
	})
	if err != nil {
		t.Fatal(err)
	}
	want := jsonRoundTripMap(t, requestBody)
	delete(want, "request_id")
	want["model"] = "provider-chat"
	if !reflect.DeepEqual(captured, want) {
		t.Fatalf("native Chat request changed\n got: %#v\nwant: %#v", captured, want)
	}
	if idempotencyKey != "gateway-task-id" {
		t.Fatalf("missing Gateway task idempotency key: %q", idempotencyKey)
	}
}

func TestOpenAIResponsesNativeDeepPassthroughPreservesOfficialAndFutureFields(t *testing.T) {
	requestBody := completeResponsesPassthroughBody()
	var captured map[string]any
	var idempotencyKey string
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		idempotencyKey = r.Header.Get("Idempotency-Key")
		if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
			t.Fatal(err)
		}
		_ = json.NewEncoder(w).Encode(map[string]any{
			"id": "resp-native", "object": "response", "status": "completed", "output": []any{},
		})
	}))
	defer server.Close()

	_, err := (OpenAIClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
		Kind: "responses", Model: "public-responses", Body: requestBody, OriginalBody: requestBody,
		UpstreamProtocol: ProtocolOpenAIResponses, UpstreamPreviousResponseID: "resp_upstream_parent",
		UpstreamIdempotencyKey: "gateway-task-id",
		Candidate: store.RuntimeModelCandidate{
			Provider: "openai", BaseURL: server.URL, ProviderModelName: "provider-responses",
			Credentials: map[string]any{"apiKey": "test-key"},
		},
	})
	if err != nil {
		t.Fatal(err)
	}
	want := jsonRoundTripMap(t, requestBody)
	delete(want, "request_id")
	want["model"] = "provider-responses"
	want["previous_response_id"] = "resp_upstream_parent"
	if !reflect.DeepEqual(captured, want) {
		t.Fatalf("native Responses request changed\n got: %#v\nwant: %#v", captured, want)
	}
	if idempotencyKey != "gateway-task-id" {
		t.Fatalf("missing Gateway task idempotency key: %q", idempotencyKey)
	}
}

func completeChatPassthroughBody() map[string]any {
	return map[string]any{
		"model": "caller-chat", "messages": []any{
			map[string]any{"role": "assistant", "content": nil, "function_call": map[string]any{"name": "legacy", "arguments": "{\"x\":1}"}},
			map[string]any{"role": "assistant", "content": nil, "tool_calls": []any{
				map[string]any{"id": "call_function", "type": "function", "function": map[string]any{"name": "lookup", "arguments": "{\"q\":1}"}},
				map[string]any{"id": "call_custom", "type": "custom", "custom": map[string]any{"name": "shell", "input": "pwd"}},
			}},
		},
		"audio": map[string]any{"format": "wav", "voice": "alloy"}, "frequency_penalty": 0.1,
		"function_call": map[string]any{"name": "legacy"}, "functions": []any{map[string]any{"name": "legacy", "parameters": map[string]any{"type": "object"}}},
		"logit_bias": map[string]any{"1": 2}, "logprobs": true, "max_completion_tokens": 101, "max_tokens": 102,
		"metadata": map[string]any{"trace": "1"}, "modalities": []any{"text"}, "moderation": map[string]any{"type": "auto"}, "n": 1,
		"parallel_tool_calls": true, "prediction": map[string]any{"type": "content", "content": "answer"}, "presence_penalty": 0.2,
		"prompt_cache_key": "cache", "prompt_cache_options": map[string]any{"type": "ephemeral"}, "prompt_cache_retention": "in_memory",
		"reasoning_effort": "low", "response_format": map[string]any{"type": "json_object"}, "safety_identifier": "safe", "seed": 7,
		"service_tier": "default", "stop": []any{"END"}, "store": false, "stream": false,
		"stream_options": map[string]any{"include_usage": true}, "temperature": 0.7,
		"tool_choice": map[string]any{"type": "custom", "custom": map[string]any{"name": "shell"}},
		"tools": []any{
			map[string]any{"type": "function", "function": map[string]any{"name": "lookup", "parameters": map[string]any{"type": "object"}}},
			map[string]any{"type": "custom", "custom": map[string]any{"name": "shell", "format": map[string]any{"type": "text"}}},
		},
		"top_logprobs": 2, "top_p": 0.9, "user": "user-1", "verbosity": "low",
		"web_search_options":    map[string]any{"search_context_size": "low"},
		"future_official_field": map[string]any{"nested": []any{map[string]any{"keep": true}}},
		"request_id":            "gateway-only",
	}
}

func completeResponsesPassthroughBody() map[string]any {
	return map[string]any{
		"background": false, "context_management": map[string]any{"type": "compaction", "compact_threshold": 2000},
		"conversation": "conv_1", "include": []any{"message.output_text.logprobs"},
		"input": []any{map[string]any{"type": "message", "role": "user", "content": []any{
			map[string]any{"type": "input_text", "text": "hello", "prompt_cache_breakpoint": map[string]any{"type": "ephemeral"}},
		}}},
		"instructions": "be concise", "max_output_tokens": 200, "max_tool_calls": 3, "metadata": map[string]any{"trace": "1"},
		"model": "caller-responses", "moderation": map[string]any{"type": "auto"}, "parallel_tool_calls": true,
		"previous_response_id": "resp_caller_parent", "prompt": map[string]any{"id": "pmpt_1", "variables": map[string]any{"x": "y"}},
		"prompt_cache_key": "cache", "prompt_cache_options": map[string]any{"type": "ephemeral"}, "prompt_cache_retention": "24h",
		"reasoning": map[string]any{"effort": "low", "summary": "auto"}, "safety_identifier": "safe", "service_tier": "default",
		"store": true, "stream": false, "stream_options": map[string]any{"include_obfuscation": true}, "temperature": 0.7,
		"text":         map[string]any{"format": map[string]any{"type": "json_schema", "name": "answer", "schema": map[string]any{"type": "object"}}, "verbosity": "low"},
		"tool_choice":  map[string]any{"type": "custom", "name": "shell"},
		"tools":        []any{map[string]any{"type": "custom", "name": "shell", "description": "run", "format": map[string]any{"type": "text"}}},
		"top_logprobs": 2, "top_p": 0.9, "truncation": "auto", "user": "user-1",
		"future_official_field": map[string]any{"nested": []any{map[string]any{"keep": true}}},
		"request_id":            "gateway-only",
	}
}

func jsonRoundTripMap(t *testing.T, value map[string]any) map[string]any {
	t.Helper()
	raw, err := json.Marshal(value)
	if err != nil {
		t.Fatal(err)
	}
	var out map[string]any
	if err := json.Unmarshal(raw, &out); err != nil {
		t.Fatal(err)
	}
	return out
}
