package clients

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

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

func TestGeminiGenerationConfigDropsDefaultRatioTokensAndNormalizesKSize(t *testing.T) {
	config := geminiGenerationConfig(map[string]any{
		"aspect_ratio": "auto",
		"size":         "2k",
		"generationConfig": map[string]any{
			"imageConfig": map[string]any{
				"aspectRatio": "adaptive",
				"imageSize":   "2k",
			},
		},
	}, true)

	imageConfig := mapFromAny(config["imageConfig"])
	if _, ok := imageConfig["aspectRatio"]; ok {
		t.Fatalf("non-ratio tokens must not be sent to Gemini: %+v", config)
	}
	if imageConfig["imageSize"] != "2K" {
		t.Fatalf("Gemini imageSize should use canonical K format: %+v", config)
	}
}

func TestNormalizeOfficialOpenAIImageSizeUsesModelSpecificWireFormat(t *testing.T) {
	legacy := map[string]any{
		"model":        "gpt-image-1",
		"size":         "2K",
		"width":        2048,
		"height":       1152,
		"aspect_ratio": "16:9",
	}
	normalizeOfficialOpenAIImageSize(legacy, map[string]any{
		"size":         "2K",
		"aspect_ratio": "16:9",
	})
	if legacy["size"] != "1536x1024" {
		t.Fatalf("legacy GPT Image should use an official orientation size: %+v", legacy)
	}

	flexible := map[string]any{
		"model":        "gpt-image-2",
		"size":         "2K",
		"resolution":   "2k",
		"aspect_ratio": "16:9",
	}
	normalizeOfficialOpenAIImageSize(flexible, map[string]any{
		"size":         "2K",
		"aspect_ratio": "16:9",
	})
	if flexible["size"] != "2048x1152" {
		t.Fatalf("GPT Image 2 should receive flexible pixel dimensions: %+v", flexible)
	}

	rounded := map[string]any{
		"model":        "gpt-image-2",
		"size":         "2K",
		"resolution":   "2K",
		"aspect_ratio": "3:2",
	}
	normalizeOfficialOpenAIImageSize(rounded, map[string]any{
		"size":         "2K",
		"aspect_ratio": "3:2",
	})
	if rounded["size"] != "2048x1360" {
		t.Fatalf("GPT Image 2 dimensions should satisfy the official 16-pixel multiple: %+v", rounded)
	}

	explicit := map[string]any{
		"model":  "gpt-image-2",
		"size":   "1232x768",
		"width":  1232,
		"height": 768,
	}
	normalizeOfficialOpenAIImageSize(explicit, map[string]any{
		"size": "1234x777",
	})
	if explicit["size"] != "1234x777" {
		t.Fatalf("an explicit WxH size must be sent unchanged to OpenAI: %+v", explicit)
	}

	explicitLegacy := map[string]any{
		"model": "gpt-image-1",
		"size":  "2048x1152",
	}
	normalizeOfficialOpenAIImageSize(explicitLegacy, map[string]any{
		"size": "2048x1152",
	})
	if explicitLegacy["size"] != "2048x1152" {
		t.Fatalf("explicit WxH must also win for legacy OpenAI image models: %+v", explicitLegacy)
	}
}

func TestOpenAIClientUsesOriginalWxHAndConvertsKResolution(t *testing.T) {
	received := make([]map[string]any, 0, 3)
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var body map[string]any
		if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
			t.Fatalf("decode OpenAI image request: %v", err)
		}
		received = append(received, body)
		_ = json.NewEncoder(w).Encode(map[string]any{
			"data": []any{map[string]any{"b64_json": "aW1hZ2U="}},
		})
	}))
	defer server.Close()

	candidate := store.RuntimeModelCandidate{
		BaseURL:           server.URL,
		Provider:          "openai",
		ProviderModelName: "gpt-image-2",
		ModelType:         "image_generate",
		Credentials:       map[string]any{"apiKey": "openai-key"},
	}
	requests := []Request{
		{
			Kind:      "images.generations",
			ModelType: "image_generate",
			Body: map[string]any{
				"prompt": "explicit dimensions",
				"size":   "1232x768",
				"width":  1232,
				"height": 768,
			},
			OriginalBody: map[string]any{
				"size": "1234x777",
			},
			Candidate: candidate,
		},
		{
			Kind:      "images.generations",
			ModelType: "image_generate",
			Body: map[string]any{
				"prompt":       "resolution conversion",
				"size":         "2048x1365",
				"resolution":   "2K",
				"aspect_ratio": "3:2",
				"width":        2048,
				"height":       1365,
			},
			OriginalBody: map[string]any{
				"size":         "2K",
				"aspect_ratio": "3:2",
			},
			Candidate: candidate,
		},
		{
			Kind:      "images.generations",
			ModelType: "image_generate",
			Body: map[string]any{
				"prompt":       "resolution field conversion",
				"size":         "1024x1024",
				"resolution":   "1K",
				"aspect_ratio": "1:1",
				"width":        1024,
				"height":       1024,
			},
			OriginalBody: map[string]any{
				"resolution":   "1k",
				"aspect_ratio": "1:1",
			},
			Candidate: candidate,
		},
	}
	for _, request := range requests {
		if _, err := (OpenAIClient{HTTPClient: server.Client()}).Run(context.Background(), request); err != nil {
			t.Fatalf("run OpenAI image request: %v", err)
		}
	}

	if len(received) != 3 {
		t.Fatalf("unexpected request count: %d", len(received))
	}
	if received[0]["size"] != "1234x777" {
		t.Fatalf("explicit WxH should win over preprocessed dimensions: %+v", received[0])
	}
	if received[1]["size"] != "2048x1360" {
		t.Fatalf("2K with 3:2 should use normalized OpenAI dimensions: %+v", received[1])
	}
	if received[2]["size"] != "1024x1024" {
		t.Fatalf("resolution=1K should be converted to OpenAI dimensions: %+v", received[2])
	}
	for _, body := range received {
		for _, key := range []string{"resolution", "aspect_ratio", "width", "height"} {
			if _, ok := body[key]; ok {
				t.Fatalf("generic geometry field %q must not reach OpenAI: %+v", key, body)
			}
		}
	}
}

func TestVolcesImageBodySelectsConfiguredSizeFormat(t *testing.T) {
	body := volcesImageBody(Request{
		Kind:      "images.generations",
		ModelType: "image_generate",
		Body: map[string]any{
			"model":        "Seedream-5.0-Pro",
			"resolution":   "2k",
			"size":         "2048x1152",
			"width":        2048,
			"height":       1152,
			"aspect_ratio": "16:9",
			"platformId":   "gateway-internal-platform",
		},
		Candidate: store.RuntimeModelCandidate{
			ProviderModelName: "doubao-seedream-5-0-pro-260628",
			ModelType:         "image_generate",
			Capabilities: map[string]any{
				"image_generate": map[string]any{
					"size_param_format": "resolution",
				},
			},
		},
	})
	if body["size"] != "2K" {
		t.Fatalf("resolution-only Volces model should receive canonical K size: %+v", body)
	}
	for _, key := range []string{"resolution", "width", "height", "aspect_ratio", "platformId"} {
		if _, ok := body[key]; ok {
			t.Fatalf("generic geometry field %q must not reach Volces: %+v", key, body)
		}
	}
}
